From 324e86bf1fdf23ba2485870a46ebb2950224017b Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 12 Dec 2023 15:18:35 +0100 Subject: [PATCH 01/15] Implemented progress bars for the cli --- cli/pom.xml | 6 ++ cli/src/main/java/de/jplag/cli/CLI.java | 2 +- .../main/java/de/jplag/cli/CliUiHooks.java | 44 ++++++++++ core/src/main/java/de/jplag/JPlag.java | 28 +++--- .../src/main/java/de/jplag/SubmissionSet.java | 18 ++-- .../java/de/jplag/SubmissionSetBuilder.java | 86 +++++++++---------- core/src/main/java/de/jplag/UiHooks.java | 49 +++++++++++ .../strategy/AbstractComparisonStrategy.java | 2 +- .../de/jplag/strategy/ComparisonStrategy.java | 4 +- .../strategy/ParallelComparisonStrategy.java | 12 ++- .../test/java/de/jplag/NormalizationTest.java | 6 +- .../java/de/jplag/merging/MergingTest.java | 57 ++++++------ 12 files changed, 215 insertions(+), 99 deletions(-) create mode 100644 cli/src/main/java/de/jplag/cli/CliUiHooks.java create mode 100644 core/src/main/java/de/jplag/UiHooks.java diff --git a/cli/pom.xml b/cli/pom.xml index b6812a3eb..27738be75 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -123,6 +123,12 @@ picocli 4.7.5 + + + me.tongfei + progressbar + 0.10.0 + diff --git a/cli/src/main/java/de/jplag/cli/CLI.java b/cli/src/main/java/de/jplag/cli/CLI.java index 9507a9a80..17249ee67 100644 --- a/cli/src/main/java/de/jplag/cli/CLI.java +++ b/cli/src/main/java/de/jplag/cli/CLI.java @@ -75,7 +75,7 @@ public static void main(String[] args) { if (!parseResult.isUsageHelpRequested() && !(parseResult.subcommand() != null && parseResult.subcommand().isUsageHelpRequested())) { JPlagOptions options = cli.buildOptionsFromArguments(parseResult); - JPlagResult result = JPlag.run(options); + JPlagResult result = new JPlag(options, new CliUiHooks()).run(); ReportObjectFactory reportObjectFactory = new ReportObjectFactory(); reportObjectFactory.createAndSaveReport(result, cli.getResultFolder()); } diff --git a/cli/src/main/java/de/jplag/cli/CliUiHooks.java b/cli/src/main/java/de/jplag/cli/CliUiHooks.java new file mode 100644 index 000000000..17cb1982a --- /dev/null +++ b/cli/src/main/java/de/jplag/cli/CliUiHooks.java @@ -0,0 +1,44 @@ +package de.jplag.cli; + +import de.jplag.UiHooks; + +import me.tongfei.progressbar.ProgressBar; +import me.tongfei.progressbar.ProgressBarBuilder; +import me.tongfei.progressbar.ProgressBarStyle; + +/** + * Provides progress bars for the cli + */ +public class CliUiHooks implements UiHooks { + private ProgressBar currentProgressBar; + + @Override + public void startMultiStep(ProgressBarType progressBar, int count) { + this.currentProgressBar = new ProgressBarBuilder().setTaskName(this.getProgressBarName(progressBar)).setInitialMax(count) + .setStyle(ProgressBarStyle.UNICODE_BLOCK).build(); + } + + @Override + public void multiStepStep() { + if (this.currentProgressBar != null) { + this.currentProgressBar.step(); + this.currentProgressBar.refresh(); + } + } + + @Override + public void multiStepDone() { + if (this.currentProgressBar != null) { + this.currentProgressBar.close(); + this.currentProgressBar = null; + } + } + + private String getProgressBarName(ProgressBarType progressBarType) { + return switch (progressBarType) { + case LOADING -> "Loading Submissions "; + case PARSING -> "Parsing Submissions "; + case COMPARING -> "Comparing Submissions"; + }; + } +} diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index 16bafb1da..d5d6719f1 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -24,6 +24,8 @@ public class JPlag { public static final Version JPLAG_VERSION = loadVersion(); + private final UiHooks uiHooks; + private static Version loadVersion() { ResourceBundle versionProperties = ResourceBundle.getBundle("de.jplag.version"); String versionString = versionProperties.getString("version"); @@ -35,43 +37,49 @@ private static Version loadVersion() { /** * Creates and initializes a JPlag instance, parameterized by a set of options. - * @deprecated in favor of static {@link #run(JPlagOptions)}. * @param options determines the parameterization. */ - @Deprecated(since = "4.3.0") public JPlag(JPlagOptions options) { + this(options, UiHooks.NullUiHooks); + } + + /** + * Creates and initializes a JPlag instance, parameterized by a set of options. + * @param options determines the parameterization. + * @param uiHooks Used to notify the ui of state changes + */ + public JPlag(JPlagOptions options, UiHooks uiHooks) { this.options = options; + this.uiHooks = uiHooks; } /** * Main procedure, executes the comparison of source code submissions. - * @deprecated in favor of static {@link #run(JPlagOptions)}. + * @param options determines the parameterization. * @return the results of the comparison, specifically the submissions whose similarity exceeds a set threshold. * @throws ExitException if JPlag exits preemptively. */ - @Deprecated(since = "4.3.0") - public JPlagResult run() throws ExitException { - return run(options); + public static JPlagResult run(JPlagOptions options) throws ExitException { + return new JPlag(options).run(); } /** * Main procedure, executes the comparison of source code submissions. - * @param options determines the parameterization. * @return the results of the comparison, specifically the submissions whose similarity exceeds a set threshold. * @throws ExitException if JPlag exits preemptively. */ - public static JPlagResult run(JPlagOptions options) throws ExitException { + public JPlagResult run() throws ExitException { GreedyStringTiling coreAlgorithm = new GreedyStringTiling(options); ComparisonStrategy comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm); // Parse and validate submissions. SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - SubmissionSet submissionSet = builder.buildSubmissionSet(); + SubmissionSet submissionSet = builder.buildSubmissionSet(this.uiHooks); int submissionCount = submissionSet.numberOfSubmissions(); if (submissionCount < 2) throw new SubmissionException("Not enough valid submissions! (found " + submissionCount + " valid submissions)"); // Compare valid submissions. - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, this.uiHooks); // Use Match Merging against obfuscation if (options.mergingOptions().enabled()) { diff --git a/core/src/main/java/de/jplag/SubmissionSet.java b/core/src/main/java/de/jplag/SubmissionSet.java index 166a151fb..0aeef46f2 100644 --- a/core/src/main/java/de/jplag/SubmissionSet.java +++ b/core/src/main/java/de/jplag/SubmissionSet.java @@ -37,12 +37,14 @@ public class SubmissionSet { /** * @param submissions Submissions to check for plagiarism. * @param baseCode Base code submission if it exists or {@code null}. + * @param options The JPlag options + * @param uiHooks Used to notify the ui of state changes */ - public SubmissionSet(List submissions, Submission baseCode, JPlagOptions options) throws ExitException { + public SubmissionSet(List submissions, Submission baseCode, JPlagOptions options, UiHooks uiHooks) throws ExitException { this.allSubmissions = submissions; this.baseCodeSubmission = baseCode; this.options = options; - parseAllSubmissions(); + parseAllSubmissions(uiHooks); this.submissions = filterValidSubmissions(); invalidSubmissions = filterInvalidSubmissions(); } @@ -102,9 +104,9 @@ private List filterInvalidSubmissions() { return allSubmissions.stream().filter(Submission::hasErrors).toList(); } - private void parseAllSubmissions() throws ExitException { + private void parseAllSubmissions(UiHooks uiHooks) throws ExitException { try { - parseSubmissions(allSubmissions); + parseSubmissions(allSubmissions, uiHooks); if (baseCodeSubmission != null) { parseBaseCodeSubmission(baseCodeSubmission); } @@ -133,8 +135,10 @@ private void parseBaseCodeSubmission(Submission baseCode) throws BasecodeExcepti /** * Parse all given submissions. + * @param submissions The list of submissions + * @param uiHooks Used to notify the ui of state changes */ - private void parseSubmissions(List submissions) { + private void parseSubmissions(List submissions, UiHooks uiHooks) { if (submissions.isEmpty()) { logger.warn("No submissions to parse!"); return; @@ -143,8 +147,8 @@ private void parseSubmissions(List submissions) { long startTime = System.currentTimeMillis(); int tooShort = 0; + uiHooks.startMultiStep(UiHooks.ProgressBarType.PARSING, submissions.size()); for (Submission submission : submissions) { - logger.info("Parsing submission {}", submission.getName()); boolean ok; logger.trace("------ Parsing submission: " + submission.getName()); @@ -168,7 +172,9 @@ private void parseSubmissions(List submissions) { } else { logger.error("ERROR -> Submission {} removed", currentSubmissionName); } + uiHooks.multiStepStep(); } + uiHooks.multiStepDone(); int validSubmissions = submissions.size() - errors - tooShort; logger.trace(validSubmissions + " submissions parsed successfully!"); diff --git a/core/src/main/java/de/jplag/SubmissionSetBuilder.java b/core/src/main/java/de/jplag/SubmissionSetBuilder.java index 4d93c0d44..50912411f 100644 --- a/core/src/main/java/de/jplag/SubmissionSetBuilder.java +++ b/core/src/main/java/de/jplag/SubmissionSetBuilder.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -35,9 +36,9 @@ public class SubmissionSetBuilder { /** * Creates a builder for submission sets. - * @deprecated in favor of {@link #SubmissionSetBuilder(JPlagOptions)}. * @param language is the language of the submissions. * @param options are the configured options. + * @deprecated in favor of {@link #SubmissionSetBuilder(JPlagOptions)}. */ @Deprecated(since = "4.3.0") public SubmissionSetBuilder(Language language, JPlagOptions options) { @@ -54,10 +55,11 @@ public SubmissionSetBuilder(JPlagOptions options) { /** * Builds a submission set for all submissions of a specific directory. + * @param uiHooks Used to notify the ui of state changes * @return the newly built submission set. * @throws ExitException if the directory cannot be read. */ - public SubmissionSet buildSubmissionSet() throws ExitException { + public SubmissionSet buildSubmissionSet(UiHooks uiHooks) throws ExitException { Set submissionDirectories = verifyRootDirectories(options.submissionDirectories(), true); Set oldSubmissionDirectories = verifyRootDirectories(options.oldSubmissionDirectories(), false); checkForNonOverlappingRootDirectories(submissionDirectories, oldSubmissionDirectories); @@ -67,14 +69,21 @@ public SubmissionSet buildSubmissionSet() throws ExitException { int numberOfRootDirectories = submissionDirectories.size() + oldSubmissionDirectories.size(); boolean multipleRoots = (numberOfRootDirectories > 1); - // Collect valid looking entries from the root directories. - Map foundSubmissions = new HashMap<>(); - for (File directory : submissionDirectories) { - processRootDirectoryEntries(directory, multipleRoots, foundSubmissions, true); + List submissionFiles = new ArrayList<>(); + for (File submissionDirectory : submissionDirectories) { + submissionFiles.addAll(listSubmissionFiles(submissionDirectory, true)); } - for (File oldDirectory : oldSubmissionDirectories) { - processRootDirectoryEntries(oldDirectory, multipleRoots, foundSubmissions, false); + for (File submissionDirectory : oldSubmissionDirectories) { + submissionFiles.addAll(listSubmissionFiles(submissionDirectory, false)); + } + + uiHooks.startMultiStep(UiHooks.ProgressBarType.LOADING, submissionFiles.size()); + Map foundSubmissions = new HashMap<>(); + for (SubmissionFileData submissionFile : submissionFiles) { + processSubmissionFile(submissionFile, multipleRoots, foundSubmissions); + uiHooks.multiStepStep(); } + uiHooks.multiStepDone(); Optional baseCodeSubmission = loadBaseCode(); baseCodeSubmission.ifPresent(baseSubmission -> foundSubmissions.remove(baseSubmission.getRoot())); @@ -84,11 +93,11 @@ public SubmissionSet buildSubmissionSet() throws ExitException { // Some languages expect a certain order, which is ensured here: if (options.language().expectsSubmissionOrder()) { - List rootFiles = foundSubmissions.values().stream().map(it -> it.getRoot()).toList(); + List rootFiles = foundSubmissions.values().stream().map(Submission::getRoot).toList(); rootFiles = options.language().customizeSubmissionOrder(rootFiles); submissions = new ArrayList<>(rootFiles.stream().map(foundSubmissions::get).toList()); } - return new SubmissionSet(submissions, baseCodeSubmission.orElse(null), options); + return new SubmissionSet(submissions, baseCodeSubmission.orElse(null), options, uiHooks); } /** @@ -155,31 +164,25 @@ private Optional loadBaseCode() throws ExitException { Submission baseCodeSubmission = processSubmission(baseCodeSubmissionDirectory.getName(), baseCodeSubmissionDirectory, false); logger.info("Basecode directory \"{}\" will be used.", baseCodeSubmission.getName()); - return Optional.ofNullable(baseCodeSubmission); + return Optional.of(baseCodeSubmission); } - /** - * Read entries in the given root directory. - */ - private String[] listSubmissionFiles(File rootDirectory) throws ExitException { + private List listSubmissionFiles(File rootDirectory, boolean isNew) throws RootDirectoryException { if (!rootDirectory.isDirectory()) { throw new AssertionError("Given root is not a directory."); } - String[] fileNames; - try { - fileNames = rootDirectory.list(); + File[] files = rootDirectory.listFiles(); + if (files == null) { + throw new RootDirectoryException("Cannot list files of the root directory!"); + } + + return Arrays.stream(files).sorted(Comparator.comparing(File::getName)).map(it -> new SubmissionFileData(it, rootDirectory, isNew)) + .toList(); } catch (SecurityException exception) { throw new RootDirectoryException("Cannot list files of the root directory! " + exception.getMessage(), exception); } - - if (fileNames == null) { - throw new RootDirectoryException("Cannot list files of the root directory!"); - } - - Arrays.sort(fileNames); - return fileNames; } /** @@ -200,6 +203,7 @@ private String isExcludedEntry(File submissionEntry) { /** * Process the given directory entry as a submission, the path MUST not be excluded. + * @param submissionName The name of the submission * @param submissionFile the file for the submission. * @param isNew states whether submissions found in the root directory must be checked for plagiarism. * @return The entry converted to a submission. @@ -225,27 +229,16 @@ private Submission processSubmission(String submissionName, File submissionFile, return new Submission(submissionName, submissionFile, isNew, parseFilesRecursively(submissionFile), options.language()); } - /** - * Process entries in the root directory to check whether they qualify as submissions. - * @param rootDirectory is the root directory being examined. - * @param foundSubmissions Submissions found so far, is updated in-place. - * @param isNew states whether submissions found in the root directory must be checked for plagiarism. - */ - private void processRootDirectoryEntries(File rootDirectory, boolean multipleRoots, Map foundSubmissions, boolean isNew) - throws ExitException { - for (String fileName : listSubmissionFiles(rootDirectory)) { - File submissionFile = new File(rootDirectory, fileName); - - String errorMessage = isExcludedEntry(submissionFile); - if (errorMessage == null) { - String rootDirectoryPrefix = multipleRoots ? (rootDirectory.getName() + File.separator) : ""; - String submissionName = rootDirectoryPrefix + fileName; - Submission submission = processSubmission(submissionName, submissionFile, isNew); - foundSubmissions.put(submission.getRoot(), submission); - } else { - logger.error(errorMessage); - } + private void processSubmissionFile(SubmissionFileData file, boolean multipleRoots, Map foundSubmissions) throws ExitException { + String errorMessage = isExcludedEntry(file.submissionFile); + if (errorMessage != null) { + logger.error(errorMessage); } + + String rootDirectoryPrefix = multipleRoots ? (file.root.getName() + File.separator) : ""; + String submissionName = rootDirectoryPrefix + file.submissionFile.getName(); + Submission submission = processSubmission(submissionName, file.submissionFile, file.isNew); + foundSubmissions.put(submission.getRoot(), submission); } /** @@ -311,4 +304,7 @@ private File makeCanonical(File file, Function excepti throw exceptionWrapper.apply(exception); } } + + private record SubmissionFileData(File submissionFile, File root, boolean isNew) { + } } diff --git a/core/src/main/java/de/jplag/UiHooks.java b/core/src/main/java/de/jplag/UiHooks.java new file mode 100644 index 000000000..f1c0af8df --- /dev/null +++ b/core/src/main/java/de/jplag/UiHooks.java @@ -0,0 +1,49 @@ +package de.jplag; + +/** + * Notifies the ui of state changes in JPlag + */ +public interface UiHooks { + /** + * A null ui hook, that does nothing + */ + UiHooks NullUiHooks = new UiHooks() { + @Override + public void startMultiStep(ProgressBarType progressBar, int count) { + } + + @Override + public void multiStepStep() { + } + + @Override + public void multiStepDone() { + } + }; + + /** + * Starts a new multi-step process + * @param progressBar The type of process + * @param count The number of steps + */ + void startMultiStep(ProgressBarType progressBar, int count); + + /** + * Advances the process by one step + */ + void multiStepStep(); + + /** + * Ends the multi-step process + */ + void multiStepDone(); + + /** + * The available processes + */ + enum ProgressBarType { + LOADING, + PARSING, + COMPARING + } +} diff --git a/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java index 19822ef41..87a5a89ee 100644 --- a/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java @@ -46,7 +46,7 @@ protected void compareSubmissionsToBaseCode(SubmissionSet submissionSet) { */ protected Optional compareSubmissions(Submission first, Submission second) { JPlagComparison comparison = greedyStringTiling.compare(first, second); - logger.info("Comparing {}-{}: {}", first.getName(), second.getName(), comparison.similarity()); + logger.trace("Comparing {}-{}: {}", first.getName(), second.getName(), comparison.similarity()); if (options.similarityMetric().isAboveThreshold(comparison, options.similarityThreshold())) { return Optional.of(comparison); diff --git a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java index 3194ba5f8..cdfa758c5 100644 --- a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java @@ -2,6 +2,7 @@ import de.jplag.JPlagResult; import de.jplag.SubmissionSet; +import de.jplag.UiHooks; /** * Strategy for comparing a set of submissions. @@ -11,7 +12,8 @@ public interface ComparisonStrategy { /** * Compares submissions from a set of submissions while considering a given base code. * @param submissionSet Collection of submissions with optional basecode to compare. + * @param uiHooks Used to notify the ui of state changes * @return the comparison results. */ - JPlagResult compareSubmissions(SubmissionSet submissionSet); + JPlagResult compareSubmissions(SubmissionSet submissionSet, UiHooks uiHooks); } diff --git a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java index fd94b9293..9160c9a66 100644 --- a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java @@ -7,6 +7,7 @@ import de.jplag.JPlagComparison; import de.jplag.JPlagResult; import de.jplag.SubmissionSet; +import de.jplag.UiHooks; import de.jplag.options.JPlagOptions; /** @@ -19,7 +20,7 @@ public ParallelComparisonStrategy(JPlagOptions options, GreedyStringTiling greed } @Override - public JPlagResult compareSubmissions(SubmissionSet submissionSet) { + public JPlagResult compareSubmissions(SubmissionSet submissionSet, UiHooks uiHooks) { // Initialize: long timeBeforeStartInMillis = System.currentTimeMillis(); boolean withBaseCode = submissionSet.hasBaseCode(); @@ -28,8 +29,13 @@ public JPlagResult compareSubmissions(SubmissionSet submissionSet) { } List tuples = buildComparisonTuples(submissionSet.getSubmissions()); - List comparisons = tuples.stream().parallel().map(tuple -> compareSubmissions(tuple.left(), tuple.right())) - .flatMap(Optional::stream).toList(); + uiHooks.startMultiStep(UiHooks.ProgressBarType.COMPARING, tuples.size()); + List comparisons = tuples.stream().parallel().map(tuple -> { + Optional result = compareSubmissions(tuple.left(), tuple.right()); + uiHooks.multiStepStep(); + return result; + }).flatMap(Optional::stream).toList(); + uiHooks.multiStepDone(); long durationInMillis = System.currentTimeMillis() - timeBeforeStartInMillis; return new JPlagResult(comparisons, submissionSet, durationInMillis, options); diff --git a/core/src/test/java/de/jplag/NormalizationTest.java b/core/src/test/java/de/jplag/NormalizationTest.java index f2e447b1c..d25eae934 100644 --- a/core/src/test/java/de/jplag/NormalizationTest.java +++ b/core/src/test/java/de/jplag/NormalizationTest.java @@ -12,13 +12,13 @@ import de.jplag.options.JPlagOptions; class NormalizationTest extends TestBase { - private Map> tokenStringMap; - private List originalTokenString; + private final Map> tokenStringMap; + private final List originalTokenString; NormalizationTest() throws ExitException { JPlagOptions options = getDefaultOptions("normalization"); SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - SubmissionSet submissionSet = builder.buildSubmissionSet(); + SubmissionSet submissionSet = builder.buildSubmissionSet(UiHooks.NullUiHooks); submissionSet.normalizeSubmissions(); Function> getTokenString = submission -> submission.getTokenList().stream().map(Token::getType).toList(); tokenStringMap = submissionSet.getSubmissions().stream().collect(Collectors.toMap(Submission::getName, getTokenString)); diff --git a/core/src/test/java/de/jplag/merging/MergingTest.java b/core/src/test/java/de/jplag/merging/MergingTest.java index 0d6780b9f..c7be3021c 100644 --- a/core/src/test/java/de/jplag/merging/MergingTest.java +++ b/core/src/test/java/de/jplag/merging/MergingTest.java @@ -1,17 +1,5 @@ package de.jplag.merging; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - import de.jplag.GreedyStringTiling; import de.jplag.JPlagComparison; import de.jplag.JPlagResult; @@ -21,10 +9,22 @@ import de.jplag.SubmissionSetBuilder; import de.jplag.TestBase; import de.jplag.Token; +import de.jplag.UiHooks; import de.jplag.exceptions.ExitException; import de.jplag.options.JPlagOptions; import de.jplag.strategy.ComparisonStrategy; import de.jplag.strategy.ParallelComparisonStrategy; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * This class extends on {@link TestBase} and performs several test on Match Merging, in order to check its @@ -33,15 +33,14 @@ * CC BY 4.0 license. */ class MergingTest extends TestBase { - private JPlagOptions options; - private JPlagResult result; + private final JPlagOptions options; private List matches; private List comparisonsBefore; private List comparisonsAfter; - private ComparisonStrategy comparisonStrategy; - private SubmissionSet submissionSet; - private final int MINIMUM_NEIGHBOR_LENGTH = 1; - private final int MAXIMUM_GAP_SIZE = 10; + private final ComparisonStrategy comparisonStrategy; + private final SubmissionSet submissionSet; + private static final int MINIMUM_NEIGHBOR_LENGTH = 1; + private static final int MAXIMUM_GAP_SIZE = 10; MergingTest() throws ExitException { options = getDefaultOptions("merging").withMergingOptions(new MergingOptions(true, MINIMUM_NEIGHBOR_LENGTH, MAXIMUM_GAP_SIZE)); @@ -50,12 +49,12 @@ class MergingTest extends TestBase { comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm); SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - submissionSet = builder.buildSubmissionSet(); + submissionSet = builder.buildSubmissionSet(UiHooks.NullUiHooks); } @BeforeEach void prepareTestState() { - result = comparisonStrategy.compareSubmissions(submissionSet); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, UiHooks.NullUiHooks); comparisonsBefore = result.getAllComparisons(); if (options.mergingOptions().enabled()) { @@ -83,10 +82,10 @@ void testGSTIgnoredMatches() { } private void checkMatchLength(Function> matchFunction, int threshold, List comparisons) { - for (int i = 0; i < comparisons.size(); i++) { - matches = matchFunction.apply(comparisons.get(i)); - for (int j = 0; j < matches.size(); j++) { - assertTrue(matches.get(j).length() >= threshold); + for (JPlagComparison comparison : comparisons) { + matches = matchFunction.apply(comparison); + for (Match match : matches) { + assertTrue(match.length() >= threshold); } } } @@ -169,11 +168,11 @@ void testCorrectMerges() { matches = comparisonsAfter.get(i).matches(); List sortedByFirst = new ArrayList<>(comparisonsBefore.get(i).matches()); sortedByFirst.addAll(comparisonsBefore.get(i).ignoredMatches()); - Collections.sort(sortedByFirst, (m1, m2) -> m1.startOfFirst() - m2.startOfFirst()); - for (int j = 0; j < matches.size(); j++) { + sortedByFirst.sort(Comparator.comparingInt(Match::startOfFirst)); + for (Match match : matches) { int begin = -1; for (int k = 0; k < sortedByFirst.size(); k++) { - if (sortedByFirst.get(k).startOfFirst() == matches.get(j).startOfFirst()) { + if (sortedByFirst.get(k).startOfFirst() == match.startOfFirst()) { begin = k; break; } @@ -182,10 +181,10 @@ void testCorrectMerges() { correctMerges = false; } else { int foundToken = 0; - while (foundToken < matches.get(j).length()) { + while (foundToken < match.length()) { foundToken += sortedByFirst.get(begin).length(); begin++; - if (foundToken > matches.get(j).length()) { + if (foundToken > match.length()) { correctMerges = false; } } From 9d864d094d06a9d24e786b143b23bf792707cf53 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 12 Dec 2023 15:20:42 +0100 Subject: [PATCH 02/15] Spotless --- .../java/de/jplag/merging/MergingTest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/test/java/de/jplag/merging/MergingTest.java b/core/src/test/java/de/jplag/merging/MergingTest.java index c7be3021c..c2c43bdca 100644 --- a/core/src/test/java/de/jplag/merging/MergingTest.java +++ b/core/src/test/java/de/jplag/merging/MergingTest.java @@ -1,5 +1,17 @@ package de.jplag.merging; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + import de.jplag.GreedyStringTiling; import de.jplag.JPlagComparison; import de.jplag.JPlagResult; @@ -14,17 +26,6 @@ import de.jplag.options.JPlagOptions; import de.jplag.strategy.ComparisonStrategy; import de.jplag.strategy.ParallelComparisonStrategy; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.function.Function; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; /** * This class extends on {@link TestBase} and performs several test on Match Merging, in order to check its From 085f0c84f05b6824d31c064236ae6bb9c17abcd7 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 9 Jan 2024 15:44:12 +0100 Subject: [PATCH 03/15] Changed progress bar implementation to rely on a singleton instead of passing a hook object all the way through. --- cli/src/main/java/de/jplag/cli/CLI.java | 5 +- .../main/java/de/jplag/cli/CliUiHooks.java | 44 -------------- .../jplag/cli/logger/TongfeiProgressBar.java | 21 +++++++ .../logger/TongfeiProgressBarProvider.java | 25 ++++++++ core/src/main/java/de/jplag/JPlag.java | 17 +----- .../src/main/java/de/jplag/SubmissionSet.java | 21 +++---- .../java/de/jplag/SubmissionSetBuilder.java | 14 +++-- core/src/main/java/de/jplag/UiHooks.java | 49 ---------------- .../java/de/jplag/logging/ProgressBar.java | 11 ++++ .../de/jplag/logging/ProgressBarLogger.java | 58 +++++++++++++++++++ .../de/jplag/logging/ProgressBarProvider.java | 5 ++ .../de/jplag/logging/ProgressBarType.java | 10 ++++ .../de/jplag/strategy/ComparisonStrategy.java | 4 +- .../strategy/ParallelComparisonStrategy.java | 12 ++-- .../java/de/jplag/merging/MergingTest.java | 5 +- 15 files changed, 165 insertions(+), 136 deletions(-) delete mode 100644 cli/src/main/java/de/jplag/cli/CliUiHooks.java create mode 100644 cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java create mode 100644 cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java delete mode 100644 core/src/main/java/de/jplag/UiHooks.java create mode 100644 core/src/main/java/de/jplag/logging/ProgressBar.java create mode 100644 core/src/main/java/de/jplag/logging/ProgressBarLogger.java create mode 100644 core/src/main/java/de/jplag/logging/ProgressBarProvider.java create mode 100644 core/src/main/java/de/jplag/logging/ProgressBarType.java diff --git a/cli/src/main/java/de/jplag/cli/CLI.java b/cli/src/main/java/de/jplag/cli/CLI.java index 17249ee67..9e773b290 100644 --- a/cli/src/main/java/de/jplag/cli/CLI.java +++ b/cli/src/main/java/de/jplag/cli/CLI.java @@ -20,9 +20,11 @@ import de.jplag.JPlagResult; import de.jplag.Language; import de.jplag.cli.logger.CollectedLoggerFactory; +import de.jplag.cli.logger.TongfeiProgressBarProvider; import de.jplag.clustering.ClusteringOptions; import de.jplag.clustering.Preprocessing; import de.jplag.exceptions.ExitException; +import de.jplag.logging.ProgressBarLogger; import de.jplag.merging.MergingOptions; import de.jplag.options.JPlagOptions; import de.jplag.options.LanguageOption; @@ -75,7 +77,8 @@ public static void main(String[] args) { if (!parseResult.isUsageHelpRequested() && !(parseResult.subcommand() != null && parseResult.subcommand().isUsageHelpRequested())) { JPlagOptions options = cli.buildOptionsFromArguments(parseResult); - JPlagResult result = new JPlag(options, new CliUiHooks()).run(); + ProgressBarLogger.setProgressBarProvider(new TongfeiProgressBarProvider()); + JPlagResult result = new JPlag(options).run(); ReportObjectFactory reportObjectFactory = new ReportObjectFactory(); reportObjectFactory.createAndSaveReport(result, cli.getResultFolder()); } diff --git a/cli/src/main/java/de/jplag/cli/CliUiHooks.java b/cli/src/main/java/de/jplag/cli/CliUiHooks.java deleted file mode 100644 index 17cb1982a..000000000 --- a/cli/src/main/java/de/jplag/cli/CliUiHooks.java +++ /dev/null @@ -1,44 +0,0 @@ -package de.jplag.cli; - -import de.jplag.UiHooks; - -import me.tongfei.progressbar.ProgressBar; -import me.tongfei.progressbar.ProgressBarBuilder; -import me.tongfei.progressbar.ProgressBarStyle; - -/** - * Provides progress bars for the cli - */ -public class CliUiHooks implements UiHooks { - private ProgressBar currentProgressBar; - - @Override - public void startMultiStep(ProgressBarType progressBar, int count) { - this.currentProgressBar = new ProgressBarBuilder().setTaskName(this.getProgressBarName(progressBar)).setInitialMax(count) - .setStyle(ProgressBarStyle.UNICODE_BLOCK).build(); - } - - @Override - public void multiStepStep() { - if (this.currentProgressBar != null) { - this.currentProgressBar.step(); - this.currentProgressBar.refresh(); - } - } - - @Override - public void multiStepDone() { - if (this.currentProgressBar != null) { - this.currentProgressBar.close(); - this.currentProgressBar = null; - } - } - - private String getProgressBarName(ProgressBarType progressBarType) { - return switch (progressBarType) { - case LOADING -> "Loading Submissions "; - case PARSING -> "Parsing Submissions "; - case COMPARING -> "Comparing Submissions"; - }; - } -} diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java new file mode 100644 index 000000000..b6bb2d272 --- /dev/null +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java @@ -0,0 +1,21 @@ +package de.jplag.cli.logger; + +import de.jplag.logging.ProgressBar; + +public class TongfeiProgressBar implements ProgressBar { + private final me.tongfei.progressbar.ProgressBar progressBar; + + public TongfeiProgressBar(me.tongfei.progressbar.ProgressBar progressBar) { + this.progressBar = progressBar; + } + + @Override + public void step(int amount) { + this.progressBar.stepBy(amount); + } + + @Override + public void dispose() { + this.progressBar.close(); + } +} diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java new file mode 100644 index 000000000..6e09fe817 --- /dev/null +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java @@ -0,0 +1,25 @@ +package de.jplag.cli.logger; + +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarProvider; +import de.jplag.logging.ProgressBarType; + +import me.tongfei.progressbar.ProgressBarBuilder; +import me.tongfei.progressbar.ProgressBarStyle; + +public class TongfeiProgressBarProvider implements ProgressBarProvider { + @Override + public ProgressBar initProgressBar(ProgressBarType type, int totalSteps) { + me.tongfei.progressbar.ProgressBar progressBar = new ProgressBarBuilder().setTaskName(getProgressBarName(type)).setInitialMax(totalSteps) + .setStyle(ProgressBarStyle.UNICODE_BLOCK).build(); + return new TongfeiProgressBar(progressBar); + } + + private String getProgressBarName(ProgressBarType progressBarType) { + return switch (progressBarType) { + case LOADING -> "Loading Submissions "; + case PARSING -> "Parsing Submissions "; + case COMPARING -> "Comparing Submissions"; + }; + } +} diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index d5d6719f1..db9fba6dc 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -24,8 +24,6 @@ public class JPlag { public static final Version JPLAG_VERSION = loadVersion(); - private final UiHooks uiHooks; - private static Version loadVersion() { ResourceBundle versionProperties = ResourceBundle.getBundle("de.jplag.version"); String versionString = versionProperties.getString("version"); @@ -37,20 +35,9 @@ private static Version loadVersion() { /** * Creates and initializes a JPlag instance, parameterized by a set of options. - * @param options determines the parameterization. */ public JPlag(JPlagOptions options) { - this(options, UiHooks.NullUiHooks); - } - - /** - * Creates and initializes a JPlag instance, parameterized by a set of options. - * @param options determines the parameterization. - * @param uiHooks Used to notify the ui of state changes - */ - public JPlag(JPlagOptions options, UiHooks uiHooks) { this.options = options; - this.uiHooks = uiHooks; } /** @@ -73,13 +60,13 @@ public JPlagResult run() throws ExitException { ComparisonStrategy comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm); // Parse and validate submissions. SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - SubmissionSet submissionSet = builder.buildSubmissionSet(this.uiHooks); + SubmissionSet submissionSet = builder.buildSubmissionSet(); int submissionCount = submissionSet.numberOfSubmissions(); if (submissionCount < 2) throw new SubmissionException("Not enough valid submissions! (found " + submissionCount + " valid submissions)"); // Compare valid submissions. - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, this.uiHooks); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); // Use Match Merging against obfuscation if (options.mergingOptions().enabled()) { diff --git a/core/src/main/java/de/jplag/SubmissionSet.java b/core/src/main/java/de/jplag/SubmissionSet.java index 0aeef46f2..43c230ab0 100644 --- a/core/src/main/java/de/jplag/SubmissionSet.java +++ b/core/src/main/java/de/jplag/SubmissionSet.java @@ -10,6 +10,9 @@ import de.jplag.exceptions.BasecodeException; import de.jplag.exceptions.ExitException; import de.jplag.exceptions.SubmissionException; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; /** @@ -38,13 +41,12 @@ public class SubmissionSet { * @param submissions Submissions to check for plagiarism. * @param baseCode Base code submission if it exists or {@code null}. * @param options The JPlag options - * @param uiHooks Used to notify the ui of state changes */ - public SubmissionSet(List submissions, Submission baseCode, JPlagOptions options, UiHooks uiHooks) throws ExitException { + public SubmissionSet(List submissions, Submission baseCode, JPlagOptions options) throws ExitException { this.allSubmissions = submissions; this.baseCodeSubmission = baseCode; this.options = options; - parseAllSubmissions(uiHooks); + parseAllSubmissions(); this.submissions = filterValidSubmissions(); invalidSubmissions = filterInvalidSubmissions(); } @@ -104,9 +106,9 @@ private List filterInvalidSubmissions() { return allSubmissions.stream().filter(Submission::hasErrors).toList(); } - private void parseAllSubmissions(UiHooks uiHooks) throws ExitException { + private void parseAllSubmissions() throws ExitException { try { - parseSubmissions(allSubmissions, uiHooks); + parseSubmissions(allSubmissions); if (baseCodeSubmission != null) { parseBaseCodeSubmission(baseCodeSubmission); } @@ -136,9 +138,8 @@ private void parseBaseCodeSubmission(Submission baseCode) throws BasecodeExcepti /** * Parse all given submissions. * @param submissions The list of submissions - * @param uiHooks Used to notify the ui of state changes */ - private void parseSubmissions(List submissions, UiHooks uiHooks) { + private void parseSubmissions(List submissions) { if (submissions.isEmpty()) { logger.warn("No submissions to parse!"); return; @@ -147,7 +148,7 @@ private void parseSubmissions(List submissions, UiHooks uiHooks) { long startTime = System.currentTimeMillis(); int tooShort = 0; - uiHooks.startMultiStep(UiHooks.ProgressBarType.PARSING, submissions.size()); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.PARSING, submissions.size()); for (Submission submission : submissions) { boolean ok; @@ -172,9 +173,9 @@ private void parseSubmissions(List submissions, UiHooks uiHooks) { } else { logger.error("ERROR -> Submission {} removed", currentSubmissionName); } - uiHooks.multiStepStep(); + progressBar.step(); } - uiHooks.multiStepDone(); + progressBar.dispose(); int validSubmissions = submissions.size() - errors - tooShort; logger.trace(validSubmissions + " submissions parsed successfully!"); diff --git a/core/src/main/java/de/jplag/SubmissionSetBuilder.java b/core/src/main/java/de/jplag/SubmissionSetBuilder.java index 50912411f..27c8df231 100644 --- a/core/src/main/java/de/jplag/SubmissionSetBuilder.java +++ b/core/src/main/java/de/jplag/SubmissionSetBuilder.java @@ -22,6 +22,9 @@ import de.jplag.exceptions.ExitException; import de.jplag.exceptions.RootDirectoryException; import de.jplag.exceptions.SubmissionException; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; /** @@ -55,11 +58,10 @@ public SubmissionSetBuilder(JPlagOptions options) { /** * Builds a submission set for all submissions of a specific directory. - * @param uiHooks Used to notify the ui of state changes * @return the newly built submission set. * @throws ExitException if the directory cannot be read. */ - public SubmissionSet buildSubmissionSet(UiHooks uiHooks) throws ExitException { + public SubmissionSet buildSubmissionSet() throws ExitException { Set submissionDirectories = verifyRootDirectories(options.submissionDirectories(), true); Set oldSubmissionDirectories = verifyRootDirectories(options.oldSubmissionDirectories(), false); checkForNonOverlappingRootDirectories(submissionDirectories, oldSubmissionDirectories); @@ -77,13 +79,13 @@ public SubmissionSet buildSubmissionSet(UiHooks uiHooks) throws ExitException { submissionFiles.addAll(listSubmissionFiles(submissionDirectory, false)); } - uiHooks.startMultiStep(UiHooks.ProgressBarType.LOADING, submissionFiles.size()); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.LOADING, submissionFiles.size()); Map foundSubmissions = new HashMap<>(); for (SubmissionFileData submissionFile : submissionFiles) { processSubmissionFile(submissionFile, multipleRoots, foundSubmissions); - uiHooks.multiStepStep(); + progressBar.step(); } - uiHooks.multiStepDone(); + progressBar.dispose(); Optional baseCodeSubmission = loadBaseCode(); baseCodeSubmission.ifPresent(baseSubmission -> foundSubmissions.remove(baseSubmission.getRoot())); @@ -97,7 +99,7 @@ public SubmissionSet buildSubmissionSet(UiHooks uiHooks) throws ExitException { rootFiles = options.language().customizeSubmissionOrder(rootFiles); submissions = new ArrayList<>(rootFiles.stream().map(foundSubmissions::get).toList()); } - return new SubmissionSet(submissions, baseCodeSubmission.orElse(null), options, uiHooks); + return new SubmissionSet(submissions, baseCodeSubmission.orElse(null), options); } /** diff --git a/core/src/main/java/de/jplag/UiHooks.java b/core/src/main/java/de/jplag/UiHooks.java deleted file mode 100644 index f1c0af8df..000000000 --- a/core/src/main/java/de/jplag/UiHooks.java +++ /dev/null @@ -1,49 +0,0 @@ -package de.jplag; - -/** - * Notifies the ui of state changes in JPlag - */ -public interface UiHooks { - /** - * A null ui hook, that does nothing - */ - UiHooks NullUiHooks = new UiHooks() { - @Override - public void startMultiStep(ProgressBarType progressBar, int count) { - } - - @Override - public void multiStepStep() { - } - - @Override - public void multiStepDone() { - } - }; - - /** - * Starts a new multi-step process - * @param progressBar The type of process - * @param count The number of steps - */ - void startMultiStep(ProgressBarType progressBar, int count); - - /** - * Advances the process by one step - */ - void multiStepStep(); - - /** - * Ends the multi-step process - */ - void multiStepDone(); - - /** - * The available processes - */ - enum ProgressBarType { - LOADING, - PARSING, - COMPARING - } -} diff --git a/core/src/main/java/de/jplag/logging/ProgressBar.java b/core/src/main/java/de/jplag/logging/ProgressBar.java new file mode 100644 index 000000000..b7207d244 --- /dev/null +++ b/core/src/main/java/de/jplag/logging/ProgressBar.java @@ -0,0 +1,11 @@ +package de.jplag.logging; + +public interface ProgressBar { + default void step() { + step(1); + } + + void step(int amount); + + void dispose(); +} diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java new file mode 100644 index 000000000..64cc3bd5c --- /dev/null +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -0,0 +1,58 @@ +package de.jplag.logging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProgressBarLogger { + private static ProgressBarProvider progressBarProvider = new DummyProvider(); + + public static ProgressBar createProgressBar(ProgressBarType type, int totalSteps) { + return progressBarProvider.initProgressBar(type, totalSteps); + } + + public static void setProgressBarProvider(ProgressBarProvider progressBarProvider) { + ProgressBarLogger.progressBarProvider = progressBarProvider; + } + + private static class DummyProvider implements ProgressBarProvider { + @Override + public ProgressBar initProgressBar(ProgressBarType type, int totalSteps) { + return new DummyBar(type, totalSteps); + } + } + + private static class DummyBar implements ProgressBar { + private static final Logger logger = LoggerFactory.getLogger(ProgressBarLogger.class); + private int currentStep; + + public DummyBar(ProgressBarType type, int totalSteps) { + this.currentStep = 0; + logger.info(getProgressBarName(type) + "(" + totalSteps + ")"); + } + + @Override + public void step() { + logger.info("Now at step " + this.currentStep++); + } + + @Override + public void step(int amount) { + for (int i = 0; i < amount; i++) { + step(); + } + } + + @Override + public void dispose() { + logger.info("Progress bar done."); + } + + private String getProgressBarName(ProgressBarType progressBarType) { + return switch (progressBarType) { + case LOADING -> "Loading Submissions "; + case PARSING -> "Parsing Submissions "; + case COMPARING -> "Comparing Submissions"; + }; + } + } +} diff --git a/core/src/main/java/de/jplag/logging/ProgressBarProvider.java b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java new file mode 100644 index 000000000..9c17d6579 --- /dev/null +++ b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java @@ -0,0 +1,5 @@ +package de.jplag.logging; + +public interface ProgressBarProvider { + ProgressBar initProgressBar(ProgressBarType type, int totalSteps); +} diff --git a/core/src/main/java/de/jplag/logging/ProgressBarType.java b/core/src/main/java/de/jplag/logging/ProgressBarType.java new file mode 100644 index 000000000..c9668bda5 --- /dev/null +++ b/core/src/main/java/de/jplag/logging/ProgressBarType.java @@ -0,0 +1,10 @@ +package de.jplag.logging; + +/** + * The available processes + */ +public enum ProgressBarType { + LOADING, + PARSING, + COMPARING +} diff --git a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java index cdfa758c5..3194ba5f8 100644 --- a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java @@ -2,7 +2,6 @@ import de.jplag.JPlagResult; import de.jplag.SubmissionSet; -import de.jplag.UiHooks; /** * Strategy for comparing a set of submissions. @@ -12,8 +11,7 @@ public interface ComparisonStrategy { /** * Compares submissions from a set of submissions while considering a given base code. * @param submissionSet Collection of submissions with optional basecode to compare. - * @param uiHooks Used to notify the ui of state changes * @return the comparison results. */ - JPlagResult compareSubmissions(SubmissionSet submissionSet, UiHooks uiHooks); + JPlagResult compareSubmissions(SubmissionSet submissionSet); } diff --git a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java index 9160c9a66..0d4c5bbee 100644 --- a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java @@ -7,7 +7,9 @@ import de.jplag.JPlagComparison; import de.jplag.JPlagResult; import de.jplag.SubmissionSet; -import de.jplag.UiHooks; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; /** @@ -20,7 +22,7 @@ public ParallelComparisonStrategy(JPlagOptions options, GreedyStringTiling greed } @Override - public JPlagResult compareSubmissions(SubmissionSet submissionSet, UiHooks uiHooks) { + public JPlagResult compareSubmissions(SubmissionSet submissionSet) { // Initialize: long timeBeforeStartInMillis = System.currentTimeMillis(); boolean withBaseCode = submissionSet.hasBaseCode(); @@ -29,13 +31,13 @@ public JPlagResult compareSubmissions(SubmissionSet submissionSet, UiHooks uiHoo } List tuples = buildComparisonTuples(submissionSet.getSubmissions()); - uiHooks.startMultiStep(UiHooks.ProgressBarType.COMPARING, tuples.size()); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, tuples.size()); List comparisons = tuples.stream().parallel().map(tuple -> { Optional result = compareSubmissions(tuple.left(), tuple.right()); - uiHooks.multiStepStep(); + progressBar.step(); return result; }).flatMap(Optional::stream).toList(); - uiHooks.multiStepDone(); + progressBar.dispose(); long durationInMillis = System.currentTimeMillis() - timeBeforeStartInMillis; return new JPlagResult(comparisons, submissionSet, durationInMillis, options); diff --git a/core/src/test/java/de/jplag/merging/MergingTest.java b/core/src/test/java/de/jplag/merging/MergingTest.java index c2c43bdca..e5062774d 100644 --- a/core/src/test/java/de/jplag/merging/MergingTest.java +++ b/core/src/test/java/de/jplag/merging/MergingTest.java @@ -21,7 +21,6 @@ import de.jplag.SubmissionSetBuilder; import de.jplag.TestBase; import de.jplag.Token; -import de.jplag.UiHooks; import de.jplag.exceptions.ExitException; import de.jplag.options.JPlagOptions; import de.jplag.strategy.ComparisonStrategy; @@ -50,12 +49,12 @@ class MergingTest extends TestBase { comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm); SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - submissionSet = builder.buildSubmissionSet(UiHooks.NullUiHooks); + submissionSet = builder.buildSubmissionSet(); } @BeforeEach void prepareTestState() { - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, UiHooks.NullUiHooks); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); comparisonsBefore = result.getAllComparisons(); if (options.mergingOptions().enabled()) { From 1b7a1c48669625e7d849a0665fc32449ec8e3a71 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 9 Jan 2024 15:47:05 +0100 Subject: [PATCH 04/15] Fixed error in NormalizationTest from previous commit. --- core/src/test/java/de/jplag/NormalizationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/de/jplag/NormalizationTest.java b/core/src/test/java/de/jplag/NormalizationTest.java index d25eae934..c6a9db9ed 100644 --- a/core/src/test/java/de/jplag/NormalizationTest.java +++ b/core/src/test/java/de/jplag/NormalizationTest.java @@ -18,7 +18,7 @@ class NormalizationTest extends TestBase { NormalizationTest() throws ExitException { JPlagOptions options = getDefaultOptions("normalization"); SubmissionSetBuilder builder = new SubmissionSetBuilder(options); - SubmissionSet submissionSet = builder.buildSubmissionSet(UiHooks.NullUiHooks); + SubmissionSet submissionSet = builder.buildSubmissionSet(); submissionSet.normalizeSubmissions(); Function> getTokenString = submission -> submission.getTokenList().stream().map(Token::getType).toList(); tokenStringMap = submissionSet.getSubmissions().stream().collect(Collectors.toMap(Submission::getName, getTokenString)); From 24c1df39a2cbbb6181857dada3f4e805ce26f2f3 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 30 Jan 2024 15:33:05 +0100 Subject: [PATCH 05/15] Reverted old changes to JPlag.java, due to the different solution for progress bars. --- core/src/main/java/de/jplag/JPlag.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index db9fba6dc..16bafb1da 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -35,27 +35,32 @@ private static Version loadVersion() { /** * Creates and initializes a JPlag instance, parameterized by a set of options. + * @deprecated in favor of static {@link #run(JPlagOptions)}. + * @param options determines the parameterization. */ + @Deprecated(since = "4.3.0") public JPlag(JPlagOptions options) { this.options = options; } /** * Main procedure, executes the comparison of source code submissions. - * @param options determines the parameterization. + * @deprecated in favor of static {@link #run(JPlagOptions)}. * @return the results of the comparison, specifically the submissions whose similarity exceeds a set threshold. * @throws ExitException if JPlag exits preemptively. */ - public static JPlagResult run(JPlagOptions options) throws ExitException { - return new JPlag(options).run(); + @Deprecated(since = "4.3.0") + public JPlagResult run() throws ExitException { + return run(options); } /** * Main procedure, executes the comparison of source code submissions. + * @param options determines the parameterization. * @return the results of the comparison, specifically the submissions whose similarity exceeds a set threshold. * @throws ExitException if JPlag exits preemptively. */ - public JPlagResult run() throws ExitException { + public static JPlagResult run(JPlagOptions options) throws ExitException { GreedyStringTiling coreAlgorithm = new GreedyStringTiling(options); ComparisonStrategy comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm); // Parse and validate submissions. From 9a24ef138d98a326af113200c0d49f70489eda46 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 2 Feb 2024 10:53:46 +0100 Subject: [PATCH 06/15] Added logging and cleaned up progress bar code. --- .../de/jplag/cli/logger/TongfeiProgressBar.java | 3 +++ .../cli/logger/TongfeiProgressBarProvider.java | 3 +++ core/src/main/java/de/jplag/JPlag.java | 7 ++++++- .../main/java/de/jplag/logging/ProgressBar.java | 13 +++++++++++++ .../java/de/jplag/logging/ProgressBarLogger.java | 14 ++++++++++++++ .../java/de/jplag/logging/ProgressBarProvider.java | 9 +++++++++ .../java/de/jplag/logging/ProgressBarType.java | 2 +- .../java/de/jplag/strategy/ComparisonStrategy.java | 3 ++- .../jplag/strategy/ParallelComparisonStrategy.java | 6 +----- .../test/java/de/jplag/merging/MergingTest.java | 7 ++++++- 10 files changed, 58 insertions(+), 9 deletions(-) diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java index b6bb2d272..7f6855026 100644 --- a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java @@ -2,6 +2,9 @@ import de.jplag.logging.ProgressBar; +/** + * A ProgressBar, that used the tongfei progress bar library underneath, to show progress bars on the cli. + */ public class TongfeiProgressBar implements ProgressBar { private final me.tongfei.progressbar.ProgressBar progressBar; diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java index 6e09fe817..44bbb01c6 100644 --- a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java @@ -7,6 +7,9 @@ import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; +/** + * A ProgressBar provider, that used the tongfei progress bar library underneath, to show progress bars on the cli. + */ public class TongfeiProgressBarProvider implements ProgressBarProvider { @Override public ProgressBar initProgressBar(ProgressBarType type, int totalSteps) { diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index 16bafb1da..143f1391f 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -10,6 +10,9 @@ import de.jplag.clustering.ClusteringFactory; import de.jplag.exceptions.ExitException; import de.jplag.exceptions.SubmissionException; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.merging.MatchMerging; import de.jplag.options.JPlagOptions; import de.jplag.reporting.reportobject.model.Version; @@ -71,7 +74,9 @@ public static JPlagResult run(JPlagOptions options) throws ExitException { throw new SubmissionException("Not enough valid submissions! (found " + submissionCount + " valid submissions)"); // Compare valid submissions. - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, (submissionCount * (submissionCount - 1)) / 2); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, progressBar); + progressBar.dispose(); // Use Match Merging against obfuscation if (options.mergingOptions().enabled()) { diff --git a/core/src/main/java/de/jplag/logging/ProgressBar.java b/core/src/main/java/de/jplag/logging/ProgressBar.java index b7207d244..57e20837c 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBar.java +++ b/core/src/main/java/de/jplag/logging/ProgressBar.java @@ -1,11 +1,24 @@ package de.jplag.logging; +/** + * Exposed interactions for a running progress bar. + */ public interface ProgressBar { + /** + * Advances the progress bar by a single step + */ default void step() { step(1); } + /** + * Advances the progress bar by amount steps + * @param amount The amount of steps + */ void step(int amount); + /** + * Closes the progress bar. After this method has been called the behaviour of the other methods is undefined. + */ void dispose(); } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java index 64cc3bd5c..34dcacea2 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -3,13 +3,27 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Provides static access to the creation of progress bars. + */ public class ProgressBarLogger { private static ProgressBarProvider progressBarProvider = new DummyProvider(); + /** + * Creates a new {@link ProgressBar} + * @param type The type of the progress bar + * @param totalSteps The total number of steps + * @return The newly created progress bar + */ public static ProgressBar createProgressBar(ProgressBarType type, int totalSteps) { return progressBarProvider.initProgressBar(type, totalSteps); } + /** + * Sets the {@link ProgressBarProvider}. Should be used by the ui before calling JPlag, if progress bars should be + * shown. + * @param progressBarProvider The provider + */ public static void setProgressBarProvider(ProgressBarProvider progressBarProvider) { ProgressBarLogger.progressBarProvider = progressBarProvider; } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarProvider.java b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java index 9c17d6579..52838c48a 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarProvider.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java @@ -1,5 +1,14 @@ package de.jplag.logging; +/** + * Provides the capability to create new progress bars, to allow JPlag to access the ui. + */ public interface ProgressBarProvider { + /** + * Creates a new progress bar + * @param type The type of progress bar. Should mostly determine the name + * @param totalSteps The total amount of steps the progress bar should have + * @return The newly created bar + */ ProgressBar initProgressBar(ProgressBarType type, int totalSteps); } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarType.java b/core/src/main/java/de/jplag/logging/ProgressBarType.java index c9668bda5..731fd3346 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarType.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarType.java @@ -1,7 +1,7 @@ package de.jplag.logging; /** - * The available processes + * The available processes. Used as a hint for the ui, which step JPlag is currently performing. */ public enum ProgressBarType { LOADING, diff --git a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java index 3194ba5f8..e67783aa8 100644 --- a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java @@ -2,6 +2,7 @@ import de.jplag.JPlagResult; import de.jplag.SubmissionSet; +import de.jplag.logging.ProgressBar; /** * Strategy for comparing a set of submissions. @@ -13,5 +14,5 @@ public interface ComparisonStrategy { * @param submissionSet Collection of submissions with optional basecode to compare. * @return the comparison results. */ - JPlagResult compareSubmissions(SubmissionSet submissionSet); + JPlagResult compareSubmissions(SubmissionSet submissionSet, ProgressBar progressBar); } diff --git a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java index 0d4c5bbee..ad926863c 100644 --- a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java @@ -8,8 +8,6 @@ import de.jplag.JPlagResult; import de.jplag.SubmissionSet; import de.jplag.logging.ProgressBar; -import de.jplag.logging.ProgressBarLogger; -import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; /** @@ -22,7 +20,7 @@ public ParallelComparisonStrategy(JPlagOptions options, GreedyStringTiling greed } @Override - public JPlagResult compareSubmissions(SubmissionSet submissionSet) { + public JPlagResult compareSubmissions(SubmissionSet submissionSet, ProgressBar progressBar) { // Initialize: long timeBeforeStartInMillis = System.currentTimeMillis(); boolean withBaseCode = submissionSet.hasBaseCode(); @@ -31,13 +29,11 @@ public JPlagResult compareSubmissions(SubmissionSet submissionSet) { } List tuples = buildComparisonTuples(submissionSet.getSubmissions()); - ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, tuples.size()); List comparisons = tuples.stream().parallel().map(tuple -> { Optional result = compareSubmissions(tuple.left(), tuple.right()); progressBar.step(); return result; }).flatMap(Optional::stream).toList(); - progressBar.dispose(); long durationInMillis = System.currentTimeMillis() - timeBeforeStartInMillis; return new JPlagResult(comparisons, submissionSet, durationInMillis, options); diff --git a/core/src/test/java/de/jplag/merging/MergingTest.java b/core/src/test/java/de/jplag/merging/MergingTest.java index e5062774d..a1fed7219 100644 --- a/core/src/test/java/de/jplag/merging/MergingTest.java +++ b/core/src/test/java/de/jplag/merging/MergingTest.java @@ -22,6 +22,9 @@ import de.jplag.TestBase; import de.jplag.Token; import de.jplag.exceptions.ExitException; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; import de.jplag.strategy.ComparisonStrategy; import de.jplag.strategy.ParallelComparisonStrategy; @@ -54,7 +57,9 @@ class MergingTest extends TestBase { @BeforeEach void prepareTestState() { - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, 0); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, progressBar); + progressBar.dispose(); comparisonsBefore = result.getAllComparisons(); if (options.mergingOptions().enabled()) { From 33d84ac416aadca730225557e2ce023210de93f9 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 6 Feb 2024 15:32:47 +0100 Subject: [PATCH 07/15] Changed the implementation of the progress bar for the comparison. --- core/src/main/java/de/jplag/JPlag.java | 7 +-- .../strategy/AbstractComparisonStrategy.java | 47 ++++++++++++++++++- .../de/jplag/strategy/ComparisonStrategy.java | 3 +- .../strategy/ParallelComparisonStrategy.java | 23 ++++----- .../java/de/jplag/merging/MergingTest.java | 7 +-- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/de/jplag/JPlag.java b/core/src/main/java/de/jplag/JPlag.java index 143f1391f..16bafb1da 100644 --- a/core/src/main/java/de/jplag/JPlag.java +++ b/core/src/main/java/de/jplag/JPlag.java @@ -10,9 +10,6 @@ import de.jplag.clustering.ClusteringFactory; import de.jplag.exceptions.ExitException; import de.jplag.exceptions.SubmissionException; -import de.jplag.logging.ProgressBar; -import de.jplag.logging.ProgressBarLogger; -import de.jplag.logging.ProgressBarType; import de.jplag.merging.MatchMerging; import de.jplag.options.JPlagOptions; import de.jplag.reporting.reportobject.model.Version; @@ -74,9 +71,7 @@ public static JPlagResult run(JPlagOptions options) throws ExitException { throw new SubmissionException("Not enough valid submissions! (found " + submissionCount + " valid submissions)"); // Compare valid submissions. - ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, (submissionCount * (submissionCount - 1)) / 2); - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, progressBar); - progressBar.dispose(); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); // Use Match Merging against obfuscation if (options.mergingOptions().enabled()) { diff --git a/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java index 87a5a89ee..09c8717cb 100644 --- a/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/AbstractComparisonStrategy.java @@ -3,14 +3,19 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.jplag.GreedyStringTiling; import de.jplag.JPlagComparison; +import de.jplag.JPlagResult; import de.jplag.Submission; import de.jplag.SubmissionSet; +import de.jplag.logging.ProgressBar; +import de.jplag.logging.ProgressBarLogger; +import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; public abstract class AbstractComparisonStrategy implements ComparisonStrategy { @@ -57,7 +62,7 @@ protected Optional compareSubmissions(Submission first, Submiss /** * @return a list of all submission tuples to be processed. */ - protected static List buildComparisonTuples(List submissions) { + protected List buildComparisonTuples(List submissions) { List tuples = new ArrayList<>(); List validSubmissions = submissions.stream().filter(s -> s.getTokenList() != null).toList(); @@ -72,4 +77,44 @@ protected static List buildComparisonTuples(List su } return tuples; } + + @Override + public JPlagResult compareSubmissions(SubmissionSet submissionSet) { + long timeBeforeStartInMillis = System.currentTimeMillis(); + + handleBaseCode(submissionSet); + + List tuples = buildComparisonTuples(submissionSet.getSubmissions()); + ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, tuples.size()); + List comparisons = prepareStream(tuples).flatMap(tuple -> { + Optional result = compareTuple(tuple); + progressBar.step(); + return result.stream(); + }).toList(); + progressBar.dispose(); + + long durationInMillis = System.currentTimeMillis() - timeBeforeStartInMillis; + + return new JPlagResult(comparisons, submissionSet, durationInMillis, options); + } + + /** + * Handle the parsing of the base code. + * @param submissionSet The submission set to parse + */ + protected abstract void handleBaseCode(SubmissionSet submissionSet); + + /** + * Prepare a stream for parsing the tuples. Here you can modify the tuples or the stream as necessary. + * @param tuples The tuples to stream + * @return The Stream of tuples + */ + protected abstract Stream prepareStream(List tuples); + + /** + * Compares a single tuple. Returns nothing, if the similarity is not high enough. + * @param tuple The Tuple to compare + * @return The comparison + */ + protected abstract Optional compareTuple(SubmissionTuple tuple); } diff --git a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java index e67783aa8..3194ba5f8 100644 --- a/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ComparisonStrategy.java @@ -2,7 +2,6 @@ import de.jplag.JPlagResult; import de.jplag.SubmissionSet; -import de.jplag.logging.ProgressBar; /** * Strategy for comparing a set of submissions. @@ -14,5 +13,5 @@ public interface ComparisonStrategy { * @param submissionSet Collection of submissions with optional basecode to compare. * @return the comparison results. */ - JPlagResult compareSubmissions(SubmissionSet submissionSet, ProgressBar progressBar); + JPlagResult compareSubmissions(SubmissionSet submissionSet); } diff --git a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java index ad926863c..43cc66ae6 100644 --- a/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java +++ b/core/src/main/java/de/jplag/strategy/ParallelComparisonStrategy.java @@ -2,12 +2,11 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import de.jplag.GreedyStringTiling; import de.jplag.JPlagComparison; -import de.jplag.JPlagResult; import de.jplag.SubmissionSet; -import de.jplag.logging.ProgressBar; import de.jplag.options.JPlagOptions; /** @@ -20,22 +19,20 @@ public ParallelComparisonStrategy(JPlagOptions options, GreedyStringTiling greed } @Override - public JPlagResult compareSubmissions(SubmissionSet submissionSet, ProgressBar progressBar) { - // Initialize: - long timeBeforeStartInMillis = System.currentTimeMillis(); + protected void handleBaseCode(SubmissionSet submissionSet) { boolean withBaseCode = submissionSet.hasBaseCode(); if (withBaseCode) { compareSubmissionsToBaseCode(submissionSet); } + } - List tuples = buildComparisonTuples(submissionSet.getSubmissions()); - List comparisons = tuples.stream().parallel().map(tuple -> { - Optional result = compareSubmissions(tuple.left(), tuple.right()); - progressBar.step(); - return result; - }).flatMap(Optional::stream).toList(); + @Override + protected Stream prepareStream(List tuples) { + return tuples.stream().parallel(); + } - long durationInMillis = System.currentTimeMillis() - timeBeforeStartInMillis; - return new JPlagResult(comparisons, submissionSet, durationInMillis, options); + @Override + protected Optional compareTuple(SubmissionTuple tuple) { + return compareSubmissions(tuple.left(), tuple.right()); } } diff --git a/core/src/test/java/de/jplag/merging/MergingTest.java b/core/src/test/java/de/jplag/merging/MergingTest.java index a1fed7219..e5062774d 100644 --- a/core/src/test/java/de/jplag/merging/MergingTest.java +++ b/core/src/test/java/de/jplag/merging/MergingTest.java @@ -22,9 +22,6 @@ import de.jplag.TestBase; import de.jplag.Token; import de.jplag.exceptions.ExitException; -import de.jplag.logging.ProgressBar; -import de.jplag.logging.ProgressBarLogger; -import de.jplag.logging.ProgressBarType; import de.jplag.options.JPlagOptions; import de.jplag.strategy.ComparisonStrategy; import de.jplag.strategy.ParallelComparisonStrategy; @@ -57,9 +54,7 @@ class MergingTest extends TestBase { @BeforeEach void prepareTestState() { - ProgressBar progressBar = ProgressBarLogger.createProgressBar(ProgressBarType.COMPARING, 0); - JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet, progressBar); - progressBar.dispose(); + JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet); comparisonsBefore = result.getAllComparisons(); if (options.mergingOptions().enabled()) { From ff41250e631c6bc1c961a1a32d7b110862691ab7 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 9 Feb 2024 12:02:02 +0100 Subject: [PATCH 08/15] Improved language for progress bars. --- cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java | 4 ++-- core/src/main/java/de/jplag/logging/ProgressBar.java | 4 ++-- core/src/main/java/de/jplag/logging/ProgressBarLogger.java | 4 ++-- core/src/main/java/de/jplag/logging/ProgressBarProvider.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java index 7f6855026..4305a497e 100644 --- a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBar.java @@ -13,8 +13,8 @@ public TongfeiProgressBar(me.tongfei.progressbar.ProgressBar progressBar) { } @Override - public void step(int amount) { - this.progressBar.stepBy(amount); + public void step(int number) { + this.progressBar.stepBy(number); } @Override diff --git a/core/src/main/java/de/jplag/logging/ProgressBar.java b/core/src/main/java/de/jplag/logging/ProgressBar.java index 57e20837c..04450434a 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBar.java +++ b/core/src/main/java/de/jplag/logging/ProgressBar.java @@ -13,9 +13,9 @@ default void step() { /** * Advances the progress bar by amount steps - * @param amount The amount of steps + * @param number The number of steps */ - void step(int amount); + void step(int number); /** * Closes the progress bar. After this method has been called the behaviour of the other methods is undefined. diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java index 34dcacea2..1c91aea29 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -50,8 +50,8 @@ public void step() { } @Override - public void step(int amount) { - for (int i = 0; i < amount; i++) { + public void step(int number) { + for (int i = 0; i < number; i++) { step(); } } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarProvider.java b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java index 52838c48a..13268325b 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarProvider.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarProvider.java @@ -7,7 +7,7 @@ public interface ProgressBarProvider { /** * Creates a new progress bar * @param type The type of progress bar. Should mostly determine the name - * @param totalSteps The total amount of steps the progress bar should have + * @param totalSteps The total number of steps the progress bar should have * @return The newly created bar */ ProgressBar initProgressBar(ProgressBarType type, int totalSteps); From 63e98391760df4f784667c89071715dd022116b4 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 9 Feb 2024 12:46:42 +0100 Subject: [PATCH 09/15] Moved SubmissionFileData into its own file. --- core/src/main/java/de/jplag/SubmissionFileData.java | 13 +++++++++++++ .../main/java/de/jplag/SubmissionSetBuilder.java | 10 ++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/de/jplag/SubmissionFileData.java diff --git a/core/src/main/java/de/jplag/SubmissionFileData.java b/core/src/main/java/de/jplag/SubmissionFileData.java new file mode 100644 index 000000000..91eb3edda --- /dev/null +++ b/core/src/main/java/de/jplag/SubmissionFileData.java @@ -0,0 +1,13 @@ +package de.jplag; + +import java.io.File; + +/** + * Contains the information about a single file in a submission. For single file submissions the submission file is the + * same as the root. + * @param submissionFile The file, that is part of a submission + * @param root The root of the submission + * @param isNew Indicates weather this follows the new or the old syntax + */ +public record SubmissionFileData(File submissionFile, File root, boolean isNew) { +} diff --git a/core/src/main/java/de/jplag/SubmissionSetBuilder.java b/core/src/main/java/de/jplag/SubmissionSetBuilder.java index 27c8df231..e0cf584e4 100644 --- a/core/src/main/java/de/jplag/SubmissionSetBuilder.java +++ b/core/src/main/java/de/jplag/SubmissionSetBuilder.java @@ -232,14 +232,14 @@ private Submission processSubmission(String submissionName, File submissionFile, } private void processSubmissionFile(SubmissionFileData file, boolean multipleRoots, Map foundSubmissions) throws ExitException { - String errorMessage = isExcludedEntry(file.submissionFile); + String errorMessage = isExcludedEntry(file.submissionFile()); if (errorMessage != null) { logger.error(errorMessage); } - String rootDirectoryPrefix = multipleRoots ? (file.root.getName() + File.separator) : ""; - String submissionName = rootDirectoryPrefix + file.submissionFile.getName(); - Submission submission = processSubmission(submissionName, file.submissionFile, file.isNew); + String rootDirectoryPrefix = multipleRoots ? (file.root().getName() + File.separator) : ""; + String submissionName = rootDirectoryPrefix + file.submissionFile().getName(); + Submission submission = processSubmission(submissionName, file.submissionFile(), file.isNew()); foundSubmissions.put(submission.getRoot(), submission); } @@ -307,6 +307,4 @@ private File makeCanonical(File file, Function excepti } } - private record SubmissionFileData(File submissionFile, File root, boolean isNew) { - } } From b25863ceabba862ccdcfb5dd0e533e625b9f873f Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 9 Feb 2024 12:57:29 +0100 Subject: [PATCH 10/15] Improved c++ readability. --- README.md | 4 +- docs/2.-Supported-Languages.md | 2 +- .../main/java/de/jplag/cpp2/CPPListener.java | 58 +++++++++++++------ 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 2a124620a..e94b46609 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ In the following, a list of all supported languages with their supported languag | Language | Version | CLI Argument Name | [state](https://github.com/jplag/JPlag/wiki/2.-Supported-Languages) | parser | |------------------------------------------------------------|---------------------------------------------------------------------------------------:|-------------------|:-------------------------------------------------------------------:|:---------:| | [Java](https://www.java.com) | 21 | java | mature | JavaC | -| [C/C++](https://isocpp.org) | 11 | cpp | legacy | JavaCC | -| [C/C++](https://isocpp.org) | 14 | cpp2 | beta | ANTLR 4 | +| [C](https://isocpp.org) | 11 | cpp | legacy | JavaCC | +| [C++](https://isocpp.org) | 14 | cpp2 | beta | ANTLR 4 | | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/) | 6 | csharp | beta | ANTLR 4 | | [Go](https://go.dev) | 1.17 | golang | beta | ANTLR 4 | | [Kotlin](https://kotlinlang.org) | 1.3 | kotlin | beta | ANTLR 4 | diff --git a/docs/2.-Supported-Languages.md b/docs/2.-Supported-Languages.md index b3b54345a..c89bb8ee3 100644 --- a/docs/2.-Supported-Languages.md +++ b/docs/2.-Supported-Languages.md @@ -1,4 +1,4 @@ -JPlag currently supports Java, C/C++, C#, Go, Kotlin, Python, R, Rust, Scala, Swift, and Scheme. Additionally, it has primitive support for text and prototypical support for EMF metamodels. A detailed list, including the supported language versions can be found in the [project readme](https://github.com/jplag/JPlag/blob/main/README.md#supported-languages). +JPlag currently supports Java, C, C++, C#, Go, Kotlin, Python, R, Rust, Scala, Swift, and Scheme. Additionally, it has primitive support for text and prototypical support for EMF metamodels. A detailed list, including the supported language versions can be found in the [project readme](https://github.com/jplag/JPlag/blob/main/README.md#supported-languages). The language modules differ in their maturity due to their age and different usage frequencies. Thus, each frontend has a state label: diff --git a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java index 115ec54de..6bb24ac57 100644 --- a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java +++ b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java @@ -33,29 +33,11 @@ class CPPListener extends AbstractAntlrListener { visit(FunctionDefinitionContext.class).map(FUNCTION_BEGIN, FUNCTION_END).addLocalScope().withSemantics(CodeSemantics::createControl); - visit(IterationStatementContext.class, rule -> rule.Do() != null).map(DO_BEGIN, DO_END).addLocalScope().withLoopSemantics(); - visit(IterationStatementContext.class, rule -> rule.For() != null).map(FOR_BEGIN, FOR_END).addLocalScope().withLoopSemantics(); - visit(IterationStatementContext.class, rule -> rule.While() != null && rule.Do() == null).map(WHILE_BEGIN, WHILE_END).addLocalScope() - .withLoopSemantics(); - - visit(SelectionStatementContext.class, rule -> rule.Switch() != null).map(SWITCH_BEGIN, SWITCH_END).addLocalScope() - .withSemantics(CodeSemantics::createControl); - visit(SelectionStatementContext.class, rule -> rule.If() != null).map(IF_BEGIN, IF_END).addLocalScope() - .withSemantics(CodeSemantics::createControl); - // possible problem: variable from if visible in else, but in reality is not -- doesn't really matter - visit(CPP14Parser.Else).map(ELSE).withSemantics(CodeSemantics::createControl); - - visit(LabeledStatementContext.class, rule -> rule.Case() != null).map(CASE).withSemantics(CodeSemantics::createControl); - visit(LabeledStatementContext.class, rule -> rule.Default() != null).map(DEFAULT).withSemantics(CodeSemantics::createControl); + statementRules(); visit(TryBlockContext.class).map(TRY_BEGIN, TRY_END).addLocalScope().withSemantics(CodeSemantics::createControl); visit(HandlerContext.class).map(CATCH_BEGIN, CATCH_END).addLocalScope().withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Break() != null).map(BREAK).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Continue() != null).map(CONTINUE).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Goto() != null).map(GOTO).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Return() != null).map(RETURN).withSemantics(CodeSemantics::createControl); - visit(ThrowExpressionContext.class).map(THROW).withSemantics(CodeSemantics::createControl); visit(NewExpressionContext.class, rule -> rule.newInitializer() != null).map(NEWCLASS).withSemantics(CodeSemantics::new); @@ -73,6 +55,35 @@ class CPPListener extends AbstractAntlrListener { .onEnter((rule, varReg) -> varReg.setNextVariableAccessType(VariableAccessType.WRITE)); visit(BracedInitListContext.class).map(BRACED_INIT_BEGIN, BRACED_INIT_END).withSemantics(CodeSemantics::new); + typeSpecifierRule(); + declarationRules(); + expressionRules(); + idRules(); + } + + private void statementRules() { + visit(IterationStatementContext.class, rule -> rule.Do() != null).map(DO_BEGIN, DO_END).addLocalScope().withLoopSemantics(); + visit(IterationStatementContext.class, rule -> rule.For() != null).map(FOR_BEGIN, FOR_END).addLocalScope().withLoopSemantics(); + visit(IterationStatementContext.class, rule -> rule.While() != null && rule.Do() == null).map(WHILE_BEGIN, WHILE_END).addLocalScope() + .withLoopSemantics(); + + visit(SelectionStatementContext.class, rule -> rule.Switch() != null).map(SWITCH_BEGIN, SWITCH_END).addLocalScope() + .withSemantics(CodeSemantics::createControl); + visit(SelectionStatementContext.class, rule -> rule.If() != null).map(IF_BEGIN, IF_END).addLocalScope() + .withSemantics(CodeSemantics::createControl); + // possible problem: variable from if visible in else, but in reality is not -- doesn't really matter + visit(CPP14Parser.Else).map(ELSE).withSemantics(CodeSemantics::createControl); + + visit(LabeledStatementContext.class, rule -> rule.Case() != null).map(CASE).withSemantics(CodeSemantics::createControl); + visit(LabeledStatementContext.class, rule -> rule.Default() != null).map(DEFAULT).withSemantics(CodeSemantics::createControl); + + visit(JumpStatementContext.class, rule -> rule.Break() != null).map(BREAK).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Continue() != null).map(CONTINUE).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Goto() != null).map(GOTO).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Return() != null).map(RETURN).withSemantics(CodeSemantics::createControl); + } + + private void typeSpecifierRule() { visit(SimpleTypeSpecifierContext.class, rule -> { if (hasAncestor(rule, MemberdeclarationContext.class, FunctionDefinitionContext.class)) { return true; @@ -99,7 +110,9 @@ class CPPListener extends AbstractAntlrListener { variableRegistry.registerVariable(name, scope, true); } }); + } + private void declarationRules() { mapApply(visit(SimpleDeclarationContext.class, rule -> { if (!hasAncestor(rule, FunctionBodyContext.class)) { return false; @@ -125,12 +138,17 @@ class CPPListener extends AbstractAntlrListener { varReg.setNextVariableAccessType(VariableAccessType.WRITE); } }); + } + + private void expressionRules() { visit(ConditionalExpressionContext.class, rule -> rule.Question() != null).map(QUESTIONMARK).withSemantics(CodeSemantics::new); mapApply(visit(PostfixExpressionContext.class, rule -> rule.LeftParen() != null)); visit(PostfixExpressionContext.class, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null).map(ASSIGN) .withSemantics(CodeSemantics::new).onEnter((rule, varReg) -> varReg.setNextVariableAccessType(VariableAccessType.READ_WRITE)); + } + private void idRules() { visit(UnqualifiedIdContext.class).onEnter((ctx, varReg) -> { ParserRuleContext parentCtx = ctx.getParent().getParent(); if (!parentCtx.getParent().getParent().getText().contains("(")) { @@ -141,6 +159,8 @@ class CPPListener extends AbstractAntlrListener { }); } + + private void mapApply(ContextVisitor visitor) { visitor.onExit((ctx, varReg) -> varReg.setMutableWrite(false)).onEnter((ctx, varReg) -> { varReg.addAllNonLocalVariablesAsReads(); From 46c674cff47dd3fe571d658e91a8bcb06103f27b Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 13 Feb 2024 14:10:38 +0100 Subject: [PATCH 11/15] Revert "Improved c++ readability." This reverts commit b25863ceabba862ccdcfb5dd0e533e625b9f873f. --- README.md | 4 +- docs/2.-Supported-Languages.md | 2 +- .../main/java/de/jplag/cpp2/CPPListener.java | 58 ++++++------------- 3 files changed, 22 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e94b46609..2a124620a 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ In the following, a list of all supported languages with their supported languag | Language | Version | CLI Argument Name | [state](https://github.com/jplag/JPlag/wiki/2.-Supported-Languages) | parser | |------------------------------------------------------------|---------------------------------------------------------------------------------------:|-------------------|:-------------------------------------------------------------------:|:---------:| | [Java](https://www.java.com) | 21 | java | mature | JavaC | -| [C](https://isocpp.org) | 11 | cpp | legacy | JavaCC | -| [C++](https://isocpp.org) | 14 | cpp2 | beta | ANTLR 4 | +| [C/C++](https://isocpp.org) | 11 | cpp | legacy | JavaCC | +| [C/C++](https://isocpp.org) | 14 | cpp2 | beta | ANTLR 4 | | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/) | 6 | csharp | beta | ANTLR 4 | | [Go](https://go.dev) | 1.17 | golang | beta | ANTLR 4 | | [Kotlin](https://kotlinlang.org) | 1.3 | kotlin | beta | ANTLR 4 | diff --git a/docs/2.-Supported-Languages.md b/docs/2.-Supported-Languages.md index c89bb8ee3..b3b54345a 100644 --- a/docs/2.-Supported-Languages.md +++ b/docs/2.-Supported-Languages.md @@ -1,4 +1,4 @@ -JPlag currently supports Java, C, C++, C#, Go, Kotlin, Python, R, Rust, Scala, Swift, and Scheme. Additionally, it has primitive support for text and prototypical support for EMF metamodels. A detailed list, including the supported language versions can be found in the [project readme](https://github.com/jplag/JPlag/blob/main/README.md#supported-languages). +JPlag currently supports Java, C/C++, C#, Go, Kotlin, Python, R, Rust, Scala, Swift, and Scheme. Additionally, it has primitive support for text and prototypical support for EMF metamodels. A detailed list, including the supported language versions can be found in the [project readme](https://github.com/jplag/JPlag/blob/main/README.md#supported-languages). The language modules differ in their maturity due to their age and different usage frequencies. Thus, each frontend has a state label: diff --git a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java index 6bb24ac57..115ec54de 100644 --- a/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java +++ b/languages/cpp2/src/main/java/de/jplag/cpp2/CPPListener.java @@ -33,11 +33,29 @@ class CPPListener extends AbstractAntlrListener { visit(FunctionDefinitionContext.class).map(FUNCTION_BEGIN, FUNCTION_END).addLocalScope().withSemantics(CodeSemantics::createControl); - statementRules(); + visit(IterationStatementContext.class, rule -> rule.Do() != null).map(DO_BEGIN, DO_END).addLocalScope().withLoopSemantics(); + visit(IterationStatementContext.class, rule -> rule.For() != null).map(FOR_BEGIN, FOR_END).addLocalScope().withLoopSemantics(); + visit(IterationStatementContext.class, rule -> rule.While() != null && rule.Do() == null).map(WHILE_BEGIN, WHILE_END).addLocalScope() + .withLoopSemantics(); + + visit(SelectionStatementContext.class, rule -> rule.Switch() != null).map(SWITCH_BEGIN, SWITCH_END).addLocalScope() + .withSemantics(CodeSemantics::createControl); + visit(SelectionStatementContext.class, rule -> rule.If() != null).map(IF_BEGIN, IF_END).addLocalScope() + .withSemantics(CodeSemantics::createControl); + // possible problem: variable from if visible in else, but in reality is not -- doesn't really matter + visit(CPP14Parser.Else).map(ELSE).withSemantics(CodeSemantics::createControl); + + visit(LabeledStatementContext.class, rule -> rule.Case() != null).map(CASE).withSemantics(CodeSemantics::createControl); + visit(LabeledStatementContext.class, rule -> rule.Default() != null).map(DEFAULT).withSemantics(CodeSemantics::createControl); visit(TryBlockContext.class).map(TRY_BEGIN, TRY_END).addLocalScope().withSemantics(CodeSemantics::createControl); visit(HandlerContext.class).map(CATCH_BEGIN, CATCH_END).addLocalScope().withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Break() != null).map(BREAK).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Continue() != null).map(CONTINUE).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Goto() != null).map(GOTO).withSemantics(CodeSemantics::createControl); + visit(JumpStatementContext.class, rule -> rule.Return() != null).map(RETURN).withSemantics(CodeSemantics::createControl); + visit(ThrowExpressionContext.class).map(THROW).withSemantics(CodeSemantics::createControl); visit(NewExpressionContext.class, rule -> rule.newInitializer() != null).map(NEWCLASS).withSemantics(CodeSemantics::new); @@ -55,35 +73,6 @@ class CPPListener extends AbstractAntlrListener { .onEnter((rule, varReg) -> varReg.setNextVariableAccessType(VariableAccessType.WRITE)); visit(BracedInitListContext.class).map(BRACED_INIT_BEGIN, BRACED_INIT_END).withSemantics(CodeSemantics::new); - typeSpecifierRule(); - declarationRules(); - expressionRules(); - idRules(); - } - - private void statementRules() { - visit(IterationStatementContext.class, rule -> rule.Do() != null).map(DO_BEGIN, DO_END).addLocalScope().withLoopSemantics(); - visit(IterationStatementContext.class, rule -> rule.For() != null).map(FOR_BEGIN, FOR_END).addLocalScope().withLoopSemantics(); - visit(IterationStatementContext.class, rule -> rule.While() != null && rule.Do() == null).map(WHILE_BEGIN, WHILE_END).addLocalScope() - .withLoopSemantics(); - - visit(SelectionStatementContext.class, rule -> rule.Switch() != null).map(SWITCH_BEGIN, SWITCH_END).addLocalScope() - .withSemantics(CodeSemantics::createControl); - visit(SelectionStatementContext.class, rule -> rule.If() != null).map(IF_BEGIN, IF_END).addLocalScope() - .withSemantics(CodeSemantics::createControl); - // possible problem: variable from if visible in else, but in reality is not -- doesn't really matter - visit(CPP14Parser.Else).map(ELSE).withSemantics(CodeSemantics::createControl); - - visit(LabeledStatementContext.class, rule -> rule.Case() != null).map(CASE).withSemantics(CodeSemantics::createControl); - visit(LabeledStatementContext.class, rule -> rule.Default() != null).map(DEFAULT).withSemantics(CodeSemantics::createControl); - - visit(JumpStatementContext.class, rule -> rule.Break() != null).map(BREAK).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Continue() != null).map(CONTINUE).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Goto() != null).map(GOTO).withSemantics(CodeSemantics::createControl); - visit(JumpStatementContext.class, rule -> rule.Return() != null).map(RETURN).withSemantics(CodeSemantics::createControl); - } - - private void typeSpecifierRule() { visit(SimpleTypeSpecifierContext.class, rule -> { if (hasAncestor(rule, MemberdeclarationContext.class, FunctionDefinitionContext.class)) { return true; @@ -110,9 +99,7 @@ private void typeSpecifierRule() { variableRegistry.registerVariable(name, scope, true); } }); - } - private void declarationRules() { mapApply(visit(SimpleDeclarationContext.class, rule -> { if (!hasAncestor(rule, FunctionBodyContext.class)) { return false; @@ -138,17 +125,12 @@ private void declarationRules() { varReg.setNextVariableAccessType(VariableAccessType.WRITE); } }); - } - - private void expressionRules() { visit(ConditionalExpressionContext.class, rule -> rule.Question() != null).map(QUESTIONMARK).withSemantics(CodeSemantics::new); mapApply(visit(PostfixExpressionContext.class, rule -> rule.LeftParen() != null)); visit(PostfixExpressionContext.class, rule -> rule.PlusPlus() != null || rule.MinusMinus() != null).map(ASSIGN) .withSemantics(CodeSemantics::new).onEnter((rule, varReg) -> varReg.setNextVariableAccessType(VariableAccessType.READ_WRITE)); - } - private void idRules() { visit(UnqualifiedIdContext.class).onEnter((ctx, varReg) -> { ParserRuleContext parentCtx = ctx.getParent().getParent(); if (!parentCtx.getParent().getParent().getText().contains("(")) { @@ -159,8 +141,6 @@ private void idRules() { }); } - - private void mapApply(ContextVisitor visitor) { visitor.onExit((ctx, varReg) -> varReg.setMutableWrite(false)).onEnter((ctx, varReg) -> { varReg.addAllNonLocalVariablesAsReads(); From 80e95b2c8ab3394efbed6b3944b5bb146d5858a8 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 16 Feb 2024 08:59:01 +0100 Subject: [PATCH 12/15] Removed the duplication of the progress bar names. --- .../logger/TongfeiProgressBarProvider.java | 10 +--------- .../de/jplag/logging/ProgressBarLogger.java | 10 +--------- .../de/jplag/logging/ProgressBarType.java | 19 ++++++++++++++++--- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java index 44bbb01c6..f36d6b7b9 100644 --- a/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java +++ b/cli/src/main/java/de/jplag/cli/logger/TongfeiProgressBarProvider.java @@ -13,16 +13,8 @@ public class TongfeiProgressBarProvider implements ProgressBarProvider { @Override public ProgressBar initProgressBar(ProgressBarType type, int totalSteps) { - me.tongfei.progressbar.ProgressBar progressBar = new ProgressBarBuilder().setTaskName(getProgressBarName(type)).setInitialMax(totalSteps) + me.tongfei.progressbar.ProgressBar progressBar = new ProgressBarBuilder().setTaskName(type.getDefaultText()).setInitialMax(totalSteps) .setStyle(ProgressBarStyle.UNICODE_BLOCK).build(); return new TongfeiProgressBar(progressBar); } - - private String getProgressBarName(ProgressBarType progressBarType) { - return switch (progressBarType) { - case LOADING -> "Loading Submissions "; - case PARSING -> "Parsing Submissions "; - case COMPARING -> "Comparing Submissions"; - }; - } } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java index 1c91aea29..7cff37f8c 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -41,7 +41,7 @@ private static class DummyBar implements ProgressBar { public DummyBar(ProgressBarType type, int totalSteps) { this.currentStep = 0; - logger.info(getProgressBarName(type) + "(" + totalSteps + ")"); + logger.info(type.getDefaultText() + "(" + totalSteps + ")"); } @Override @@ -60,13 +60,5 @@ public void step(int number) { public void dispose() { logger.info("Progress bar done."); } - - private String getProgressBarName(ProgressBarType progressBarType) { - return switch (progressBarType) { - case LOADING -> "Loading Submissions "; - case PARSING -> "Parsing Submissions "; - case COMPARING -> "Comparing Submissions"; - }; - } } } diff --git a/core/src/main/java/de/jplag/logging/ProgressBarType.java b/core/src/main/java/de/jplag/logging/ProgressBarType.java index 731fd3346..88e520fcc 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarType.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarType.java @@ -4,7 +4,20 @@ * The available processes. Used as a hint for the ui, which step JPlag is currently performing. */ public enum ProgressBarType { - LOADING, - PARSING, - COMPARING + LOADING("Loading Submissions "), + PARSING("Parsing Submissions "), + COMPARING("Comparing Submissions"); + + private final String defaultText; + + ProgressBarType(String defaultText) { + this.defaultText = defaultText; + } + + /** + * @return The default display text for the type + */ + public String getDefaultText() { + return defaultText; + } } From 2bd719f334c8d02d633eb1c1fddd8d2e3ae0fecc Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Fri, 16 Feb 2024 09:18:45 +0100 Subject: [PATCH 13/15] spotless --- cli/src/main/java/de/jplag/cli/CLI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/main/java/de/jplag/cli/CLI.java b/cli/src/main/java/de/jplag/cli/CLI.java index 4efb3912f..4ab78d287 100644 --- a/cli/src/main/java/de/jplag/cli/CLI.java +++ b/cli/src/main/java/de/jplag/cli/CLI.java @@ -14,8 +14,6 @@ import java.util.Set; import java.util.stream.Collectors; -import de.jplag.cli.logger.TongfeiProgressBarProvider; -import de.jplag.logging.ProgressBarLogger; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,9 +22,11 @@ import de.jplag.JPlagResult; import de.jplag.Language; import de.jplag.cli.logger.CollectedLoggerFactory; +import de.jplag.cli.logger.TongfeiProgressBarProvider; import de.jplag.clustering.ClusteringOptions; import de.jplag.clustering.Preprocessing; import de.jplag.exceptions.ExitException; +import de.jplag.logging.ProgressBarLogger; import de.jplag.merging.MergingOptions; import de.jplag.options.JPlagOptions; import de.jplag.options.LanguageOption; From fb8aa7f2c8d9a413ec30157e7fba675dad08b674 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Mon, 19 Feb 2024 15:36:03 +0100 Subject: [PATCH 14/15] Fixed sonar cloud issues. --- .../main/java/de/jplag/logging/ProgressBarLogger.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java index 7cff37f8c..cfcab33df 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -9,6 +9,10 @@ public class ProgressBarLogger { private static ProgressBarProvider progressBarProvider = new DummyProvider(); + private ProgressBarLogger() { + //Hides default constructor + } + /** * Creates a new {@link ProgressBar} * @param type The type of the progress bar @@ -36,17 +40,17 @@ public ProgressBar initProgressBar(ProgressBarType type, int totalSteps) { } private static class DummyBar implements ProgressBar { - private static final Logger logger = LoggerFactory.getLogger(ProgressBarLogger.class); + private static final Logger logger = LoggerFactory.getLogger(DummyBar.class); private int currentStep; public DummyBar(ProgressBarType type, int totalSteps) { this.currentStep = 0; - logger.info(type.getDefaultText() + "(" + totalSteps + ")"); + logger.info("{} ({})", type.getDefaultText(), totalSteps); } @Override public void step() { - logger.info("Now at step " + this.currentStep++); + logger.info("Now at step {}", this.currentStep++); } @Override From 646e80310fd35e6f5149309cfac4d7b10ff636d3 Mon Sep 17 00:00:00 2001 From: Alexander Milster Date: Tue, 20 Feb 2024 08:13:47 +0100 Subject: [PATCH 15/15] spotless --- core/src/main/java/de/jplag/logging/ProgressBarLogger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java index cfcab33df..889d391bb 100644 --- a/core/src/main/java/de/jplag/logging/ProgressBarLogger.java +++ b/core/src/main/java/de/jplag/logging/ProgressBarLogger.java @@ -10,7 +10,7 @@ public class ProgressBarLogger { private static ProgressBarProvider progressBarProvider = new DummyProvider(); private ProgressBarLogger() { - //Hides default constructor + // Hides default constructor } /**