Browse Source

Introduce a submission set builder that takes over responsibility previously located in the JPlag and Submission classes. Further de-tangles the dependencies on the JPlag class.

Timur Sağlam 5 years ago
parent
commit
3b8c2a01fe

+ 1 - 1
jplag.frontend-utils/src/main/java/de/jplag/AbstractParser.java

@@ -4,7 +4,7 @@ package de.jplag;
  * @author Emeric Kwemou
  * @date 22.01.2005
  */
-public abstract class AbstractParser { // TODO TS: We should rename this class, as all concrete parsers shadow its name.
+public abstract class AbstractParser {
     protected ErrorConsumer program;
     protected int errors = 0;
     private int errorsSum = 0;

+ 7 - 5
jplag/src/main/java/de/jplag/GreedyStringTiling.java

@@ -3,6 +3,8 @@ package de.jplag;
 import java.util.ArrayList;
 import java.util.List;
 
+import de.jplag.options.JPlagOptions;
+
 /**
  * This class implements the Greedy String Tiling algorithm as introduced by Michael Wise. However, it is very specific
  * to the classes {@link TokenList}, {@link Token}, and {@link Match}. While this class was reworked, it still contains
@@ -13,10 +15,10 @@ import java.util.List;
  */
 public class GreedyStringTiling implements TokenConstants {
 
-    private JPlag program;
+    private final JPlagOptions options;
 
-    public GreedyStringTiling(JPlag program) {
-        this.program = program;
+    public GreedyStringTiling(JPlagOptions options) {
+        this.options = options;
     }
 
     /**
@@ -124,7 +126,7 @@ public class GreedyStringTiling implements TokenConstants {
 
         // Initialize:
         JPlagComparison comparison = new JPlagComparison(firstSubmission, secondSubmission);
-        int minimumTokenMatch = program.getOptions().getMinimumTokenMatch(); // minimal required token match
+        int minimumTokenMatch = options.getMinimumTokenMatch(); // minimal required token match
 
         if (first.size() <= minimumTokenMatch || second.size() <= minimumTokenMatch) { // <= because of pivots!
             return comparison;
@@ -214,7 +216,7 @@ public class GreedyStringTiling implements TokenConstants {
             if (withBaseCode) {
                 token.marked = token.type == FILE_END || token.type == SEPARATOR_TOKEN;
             } else {
-                token.marked = token.type == FILE_END || token.type == SEPARATOR_TOKEN || (token.basecode && program.getOptions().hasBaseCode());
+                token.marked = token.type == FILE_END || token.type == SEPARATOR_TOKEN || (token.basecode && options.hasBaseCode());
             }
         }
     }

+ 8 - 150
jplag/src/main/java/de/jplag/JPlag.java

@@ -1,18 +1,8 @@
 package de.jplag;
 
-import static de.jplag.options.Verbosity.LONG;
-
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
 
 import de.jplag.options.JPlagOptions;
 import de.jplag.options.LanguageOption;
@@ -24,14 +14,12 @@ import de.jplag.strategy.ParallelComparisonStrategy;
  * This class coordinates the whole program flow.
  */
 public class JPlag {
-
     // INPUT:
-    private HashSet<String> excludedFileNames = null; // Set of file names to be excluded in comparison.
     private Language language;
 
     // CORE COMPONENTS:
     private ComparisonStrategy comparisonStrategy;
-    private GreedyStringTiling gSTiling = new GreedyStringTiling(this); // Contains the comparison logic.
+    private GreedyStringTiling coreAlgorithm; // Contains the comparison logic.
     private final JPlagOptions options;
     private final ErrorCollector errorCollector;
 
@@ -42,6 +30,7 @@ public class JPlag {
      */
     public JPlag(JPlagOptions options) throws ExitException {
         this.options = options;
+        coreAlgorithm = new GreedyStringTiling(options);
         initializeLanguage();
         initializeComparisonStrategy();
         checkBaseCodeOption();
@@ -62,13 +51,13 @@ public class JPlag {
         if (!rootDir.isDirectory()) {
             throw new ExitException(options.getRootDirectoryName() + " is not a directory!");
         }
-        readExclusionFile(); // This file contains all files names which are excluded
-
+        
         // 2. Parse and validate submissions:
-        SubmissionSet submissionSet = findSubmissions(rootDir);
+        SubmissionSetBuilder builder = new SubmissionSetBuilder(language, options, errorCollector);
+        SubmissionSet submissionSet = builder.buildSubmissionSet(rootDir);
 
         if (submissionSet.hasBaseCode()) {
-            gSTiling.createHashes(submissionSet.getBaseCode().getTokenList(), options.getMinimumTokenMatch(), true);
+            coreAlgorithm.createHashes(submissionSet.getBaseCode().getTokenList(), options.getMinimumTokenMatch(), true);
         }
 
         int submCount = submissionSet.numberOfSubmissions();
@@ -91,37 +80,6 @@ public class JPlag {
         return language;
     }
 
-    /**
-     * @return the program options which allow to configure JPlag.
-     */
-    protected JPlagOptions getOptions() {
-        return this.options; // TODO TS: Should not be accessible, as options should be set before passing them to this class.
-    }
-
-    /**
-     * Checks if a file has a valid suffix for the current language.
-     * @param file is the file to check.
-     * @return true if the file suffix matches the language.
-     */
-    public boolean hasValidSuffix(File file) {
-        String[] validSuffixes = options.getFileSuffixes();
-
-        // This is the case if either the language frontends or the CLI did not set the valid suffixes array in options
-        if (validSuffixes == null || validSuffixes.length == 0) {
-            return true;
-        }
-        return Arrays.stream(validSuffixes).anyMatch(suffix -> file.getName().endsWith(suffix));
-    }
-
-    /**
-     * Checks if a file is excluded or not.
-     */
-    public boolean isFileExcluded(File file) {
-        if (excludedFileNames == null) {
-            return false;
-        }
-        return excludedFileNames.stream().anyMatch(excludedName -> file.getName().endsWith(excludedName));
-    }
 
     /**
      * This method checks whether the base code directory value is valid.
@@ -153,34 +111,13 @@ public class JPlag {
         }
     }
 
-    /**
-     * Find all submissions in the given root directory.
-     */
-    private SubmissionSet findSubmissions(File rootDir) throws ExitException {
-        String[] fileNamesInRootDir;
-
-        try {
-            fileNamesInRootDir = rootDir.list();
-        } catch (SecurityException e) {
-            throw new ExitException("Cannot list files of the root directory! " + e.getMessage());
-        }
-
-        if (fileNamesInRootDir == null) {
-            throw new ExitException("Cannot list files of the root directory! " + "Make sure the specified root directory is in fact a directory.");
-        }
-
-        Arrays.sort(fileNamesInRootDir);
-
-        return mapFileNamesInRootDirToSubmissions(fileNamesInRootDir, rootDir);
-    }
-
     private void initializeComparisonStrategy() throws ExitException {
         switch (options.getComparisonMode()) {
         case NORMAL:
-            comparisonStrategy = new NormalComparisonStrategy(options, gSTiling);
+            comparisonStrategy = new NormalComparisonStrategy(options, coreAlgorithm);
             break;
         case PARALLEL:
-            comparisonStrategy = new ParallelComparisonStrategy(options, gSTiling);
+            comparisonStrategy = new ParallelComparisonStrategy(options, coreAlgorithm);
             break;
         default:
             throw new ExitException("Illegal comparison mode: " + options.getComparisonMode());
@@ -209,83 +146,4 @@ public class JPlag {
 
         System.out.println("Initialized language " + this.getLanguage().getName());
     }
-
-    private SubmissionSet mapFileNamesInRootDirToSubmissions(String[] fileNames, File rootDir) throws ExitException {
-        List<Submission> submissions = new ArrayList<>();
-        Optional<Submission> baseCodeSubmission = Optional.empty();
-
-        for (String fileName : fileNames) {
-            File submissionFile = new File(rootDir, fileName);
-
-            if (isFileExcluded(submissionFile)) {
-                System.out.println("Exclude submission: " + submissionFile.getName());
-                continue;
-            }
-
-            if (submissionFile.isFile() && !hasValidSuffix(submissionFile)) {
-                System.out.println("Ignore submission with invalid suffix: " + submissionFile.getName());
-                continue;
-            }
-
-            if (submissionFile.isDirectory() && options.getSubdirectoryName() != null) {
-                // Use subdirectory instead
-                submissionFile = new File(submissionFile, options.getSubdirectoryName());
-
-                if (!submissionFile.exists()) {
-                    throw new ExitException(
-                            String.format("Submission %s does not contain the given subdirectory '%s'", fileName, options.getSubdirectoryName()));
-                }
-
-                if (!submissionFile.isDirectory()) {
-                    throw new ExitException(String.format("The given subdirectory '%s' is not a directory!", options.getSubdirectoryName()));
-                }
-            }
-
-            Submission submission = new Submission(fileName, submissionFile, this);
-
-            if (options.hasBaseCode() && options.getBaseCodeSubmissionName().equals(fileName)) {
-                baseCodeSubmission = Optional.of(submission);
-            } else {
-                submissions.add(submission);
-            }
-        }
-
-        return new SubmissionSet(submissions, baseCodeSubmission, errorCollector, options);
-    }
-
-    public void print(String message, String longMessage) {
-        errorCollector.print(message, longMessage);
-    }
-
-    /*
-     * If an exclusion file is given, it is read in and all stings are saved in the set "excluded".
-     */
-    private void readExclusionFile() {
-        if (options.getExclusionFileName() == null) {
-            return;
-        }
-
-        excludedFileNames = new HashSet<>();
-
-        try {
-            BufferedReader reader = new BufferedReader(new FileReader(options.getExclusionFileName(), JPlagOptions.CHARSET));
-            String line;
-
-            while ((line = reader.readLine()) != null) {
-                excludedFileNames.add(line.trim());
-            }
-
-            reader.close();
-        } catch (IOException exception) {
-            System.out.println("Could not read exclusion file: " + exception.getMessage());
-        }
-
-        if (options.getVerbosity() == LONG) {
-            errorCollector.print(null, "Excluded files:\n");
-
-            for (String excludedFileName : excludedFileNames) {
-                errorCollector.print(null, "  " + excludedFileName + "\n");
-            }
-        }
-    }
 }

+ 23 - 53
jplag/src/main/java/de/jplag/Submission.java

@@ -13,7 +13,6 @@ import java.nio.file.Path;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 
 import de.jplag.options.JPlagOptions;
 
@@ -41,11 +40,6 @@ public class Submission implements Comparable<Submission> {
      */
     private final Collection<File> files;
 
-    /**
-     * Back-link to the main application.
-     */
-    private final JPlag program;
-
     /**
      * Whether an error occurred during parsing the submission files.
      */
@@ -56,16 +50,23 @@ public class Submission implements Comparable<Submission> {
      */
     private TokenList tokenList;
 
+    private final Language language;
+    private final ErrorCollector errorCollector;
+
     /**
+     * Creates a submission.
      * @param name Identification of the submission (directory or filename).
      * @param submissionRoot Root of the submission (either a file or a directory).
-     * @param program Back-link to the main application.
+     * @param files are the files of the submissions, if the root is a single file it should just contain one file.
+     * @param language is the language of the submission.
+     * @param errorCollector is the interface for error reporting.
      */
-    public Submission(String name, File submissionRoot, JPlag program) {
+    public Submission(String name, File submissionRoot, Collection<File> files, Language language, ErrorCollector errorCollector) {
         this.name = name;
         this.submissionRoot = submissionRoot;
-        this.program = program;
-        this.files = parseFilesRecursively(submissionRoot);
+        this.files = files;
+        this.language = language;
+        this.errorCollector = errorCollector;
     }
 
     /**
@@ -111,18 +112,18 @@ public class Submission implements Comparable<Submission> {
      * Parse files of the submission.
      * @return Whether parsing was successful.
      */
-    public boolean parse() {
+    public boolean parse(boolean debugParser) {
         if (files == null || files.size() == 0) {
-            program.print("ERROR: nothing to parse for submission \"" + name + "\"\n", null);
+            errorCollector.print("ERROR: nothing to parse for submission \"" + name + "\"\n", null);
             return false;
         }
 
         String[] relativeFilePaths = getRelativeFilePaths(submissionRoot, files);
 
-        tokenList = this.program.getLanguage().parse(submissionRoot, relativeFilePaths);
-        if (!program.getLanguage().hasErrors()) {
+        tokenList = language.parse(submissionRoot, relativeFilePaths);
+        if (!language.hasErrors()) {
             if (tokenList.size() < 3) {
-                program.print("Submission \"" + name + "\" is too short!\n", null);
+                errorCollector.print("Submission \"" + name + "\" is too short!\n", null);
                 tokenList = null;
                 hasErrors = true; // invalidate submission
                 return false;
@@ -132,7 +133,7 @@ public class Submission implements Comparable<Submission> {
 
         tokenList = null;
         hasErrors = true; // invalidate submission
-        if (program.getOptions().isDebugParser()) {
+        if (debugParser) {
             copySubmission();
         }
         return false;
@@ -198,7 +199,7 @@ public class Submission implements Comparable<Submission> {
                 FileReader reader = new FileReader(file, JPlagOptions.CHARSET);
 
                 if (size != reader.read(buffer)) {
-                    System.out.println("Not right size read from the file, " + "but I will still continue...");
+                    System.out.println("Not right size read from the file, but I will still continue...");
                 }
 
                 result[i] = buffer;
@@ -230,7 +231,7 @@ public class Submission implements Comparable<Submission> {
     public void setTokenList(TokenList tokenList) {
         this.tokenList = tokenList;
     }
-    
+
     public void markAsErroneous() {
         hasErrors = true;
     }
@@ -261,13 +262,13 @@ public class Submission implements Comparable<Submission> {
             input.close();
             output.close();
         } catch (IOException e) {
-            program.print("Error copying file: " + e.toString() + "\n", null);
+            errorCollector.print("Error copying file: " + e.toString() + "\n", null);
         }
     }
 
     /*
-     * This method is used to copy files that can not be parsed to a special folder: de/jplag/errors/java old_java scheme cpp
-     * /001/(...files...) /002/(...files...)
+     * This method is used to copy files that can not be parsed to a special folder: de/jplag/errors/java old_java scheme
+     * cpp /001/(...files...) /002/(...files...)
      */
     private void copySubmission() {
         File errorDir = null;
@@ -280,7 +281,7 @@ public class Submission implements Comparable<Submission> {
             return;
         }
 
-        errorDir = new File(errorDir, this.program.getLanguage().getShortName());
+        errorDir = new File(errorDir, language.getShortName());
 
         if (!errorDir.exists()) {
             errorDir.mkdir();
@@ -317,35 +318,4 @@ public class Submission implements Comparable<Submission> {
         return files.stream().map(File::toPath).map(baseFilePath::relativize).map(Path::toString).toArray(String[]::new);
     }
 
-    /**
-     * Recursively scan the given directory for nested files. Excluded files and files with an invalid suffix are ignored.
-     * <p>
-     * If the given file is not a directory, the input will be returned as a singleton list.
-     * @param file - File to start the scan from.
-     * @return a list of nested files.
-     */
-    private Collection<File> parseFilesRecursively(File file) {
-        if (program.isFileExcluded(file)) {
-            return Collections.emptyList();
-        }
-
-        if (file.isFile() && program.hasValidSuffix(file)) {
-            return Collections.singletonList(file);
-        }
-
-        String[] nestedFileNames = file.list();
-
-        if (nestedFileNames == null) {
-            return Collections.emptyList();
-        }
-
-        Collection<File> files = new ArrayList<>();
-
-        for (String fileName : nestedFileNames) {
-            files.addAll(parseFilesRecursively(new File(file, fileName)));
-        }
-
-        return files;
-    }
-
 }

+ 4 - 13
jplag/src/main/java/de/jplag/SubmissionSet.java

@@ -28,7 +28,6 @@ public class SubmissionSet {
 
     private final ErrorCollector errorCollector;
     private final JPlagOptions options;
-
     private int errors = 0;
     private String currentSubmissionName;
 
@@ -94,9 +93,6 @@ public class SubmissionSet {
         return allSubmissions.stream().filter(submission -> submission.hasErrors()).collect(toList());
     }
 
-    /**
-     * TODO PB: Find a better way to separate parseSubmissions(...) and parseBaseCodeSubmission(...)
-     */
     private void parseAllSubmissions() throws ExitException {
         try {
             parseSubmissions(allSubmissions);
@@ -115,21 +111,16 @@ public class SubmissionSet {
      * Parse the given base code submission.
      */
     private void parseBaseCodeSubmission(Submission baseCode) throws ExitException {
-
         long startTime = System.currentTimeMillis();
         errorCollector.print("----- Parsing basecode submission: " + baseCode.getName() + "\n", null);
-
-        if (!baseCode.parse()) {
+        if (!baseCode.parse(options.isDebugParser())) {
             errorCollector.printErrors();
             throw new ExitException("Bad basecode submission");
         }
-
         if (baseCode.getTokenList() != null && baseCode.getNumberOfTokens() < options.getMinimumTokenMatch()) {
             throw new ExitException("Basecode submission contains fewer tokens than minimum match length allows!\n");
         }
-
         errorCollector.print("\nBasecode submission parsed!\n", null);
-
         long duration = System.currentTimeMillis() - startTime;
         errorCollector.print("\n", "\nTime for parsing Basecode: " + TimeUtil.formatDuration(duration) + "\n");
 
@@ -159,7 +150,7 @@ public class SubmissionSet {
             currentSubmissionName = subm.getName();
             errorCollector.setCurrentSubmissionName(currentSubmissionName);
 
-            if (!(ok = subm.parse())) {
+            if (!(ok = subm.parse(options.isDebugParser()))) {
                 errors++;
             }
 
@@ -184,8 +175,8 @@ public class SubmissionSet {
                 + (errors != 1 ? "s!\n" : "!\n"), null);
 
         if (invalid != 0) {
-            errorCollector.print(null,
-                    invalid + ((invalid == 1) ? " submission is not valid because it contains" : " allSubmissions are not valid because they contain")
+            errorCollector.print(null, invalid + ((invalid == 1)
+                    ? " submission is not valid because it contains" : " allSubmissions are not valid because they contain")
                             + " fewer tokens than minimum match length allows.\n");
         }
 

+ 190 - 0
jplag/src/main/java/de/jplag/SubmissionSetBuilder.java

@@ -0,0 +1,190 @@
+package de.jplag;
+
+import static de.jplag.options.Verbosity.LONG;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+
+import de.jplag.options.JPlagOptions;
+
+/**
+ * Builder class for the creation of a {@link SubmissionSet}.
+ * @author Timur Saglam
+ */
+public class SubmissionSetBuilder {
+
+    private final Language language;
+    private final JPlagOptions options;
+    private final ErrorCollector errorCollector;
+    private final HashSet<String> excludedFileNames; // Set of file names to be excluded in comparison.
+
+    /**
+     * Creates a builder for submission sets.
+     * @param language is the language of the submissions.
+     * @param options are the configured options.
+     * @param errorCollector is the interface for error reporting.
+     */
+    public SubmissionSetBuilder(Language language, JPlagOptions options, ErrorCollector errorCollector) {
+        this.language = language;
+        this.options = options;
+        this.errorCollector = errorCollector;
+        excludedFileNames = readExclusionFile();
+    }
+
+    /**
+     * Builds a submission set for all submissions of a specific directory.
+     * @param rootDirectory is the specific directory.
+     * @return the newly built submission set.
+     * @throws ExitException if the directory cannot be read.
+     */
+    public SubmissionSet buildSubmissionSet(File rootDirectory) throws ExitException {
+        String[] fileNames;
+
+        try {
+            fileNames = rootDirectory.list();
+        } catch (SecurityException exception) {
+            throw new ExitException("Cannot list files of the root directory! " + exception.getMessage());
+        }
+
+        if (fileNames == null) {
+            throw new ExitException("Cannot list files of the root directory! " + "Make sure the specified root directory is in fact a directory.");
+        }
+
+        Arrays.sort(fileNames);
+
+        return mapFileNamesToSubmissions(fileNames, rootDirectory);
+    }
+
+    /**
+     * Checks if a file has a valid suffix for the current language.
+     * @param file is the file to check.
+     * @return true if the file suffix matches the language.
+     */
+    private boolean hasValidSuffix(File file) {
+        String[] validSuffixes = options.getFileSuffixes();
+
+        // This is the case if either the language frontends or the CLI did not set the valid suffixes array in options
+        if (validSuffixes == null || validSuffixes.length == 0) {
+            return true;
+        }
+        return Arrays.stream(validSuffixes).anyMatch(suffix -> file.getName().endsWith(suffix));
+    }
+
+    /**
+     * Checks if a file is excluded or not.
+     */
+    private boolean isFileExcluded(File file) {
+        return excludedFileNames.stream().anyMatch(excludedName -> file.getName().endsWith(excludedName));
+    }
+
+    private SubmissionSet mapFileNamesToSubmissions(String[] fileNames, File rootDirectory) throws ExitException {
+        List<Submission> submissions = new ArrayList<>();
+        Optional<Submission> baseCodeSubmission = Optional.empty();
+
+        for (String fileName : fileNames) {
+            File submissionFile = new File(rootDirectory, fileName);
+
+            if (isFileExcluded(submissionFile)) {
+                System.out.println("Exclude submission: " + submissionFile.getName());
+                continue;
+            }
+
+            if (submissionFile.isFile() && !hasValidSuffix(submissionFile)) {
+                System.out.println("Ignore submission with invalid suffix: " + submissionFile.getName());
+                continue;
+            }
+
+            if (submissionFile.isDirectory() && options.getSubdirectoryName() != null) {
+                // Use subdirectory instead
+                submissionFile = new File(submissionFile, options.getSubdirectoryName());
+
+                if (!submissionFile.exists()) {
+                    throw new ExitException(
+                            String.format("Submission %s does not contain the given subdirectory '%s'", fileName, options.getSubdirectoryName()));
+                }
+
+                if (!submissionFile.isDirectory()) {
+                    throw new ExitException(String.format("The given subdirectory '%s' is not a directory!", options.getSubdirectoryName()));
+                }
+            }
+
+            Submission submission = new Submission(fileName, submissionFile, parseFilesRecursively(submissionFile), language, errorCollector);
+
+            if (options.hasBaseCode() && options.getBaseCodeSubmissionName().equals(fileName)) {
+                baseCodeSubmission = Optional.of(submission);
+            } else {
+                submissions.add(submission);
+            }
+        }
+
+        return new SubmissionSet(submissions, baseCodeSubmission, errorCollector, options);
+    }
+
+    /**
+     * Recursively scan the given directory for nested files. Excluded files and files with an invalid suffix are ignored.
+     * <p>
+     * If the given file is not a directory, the input will be returned as a singleton list.
+     * @param file - File to start the scan from.
+     * @return a list of nested files.
+     */
+    private Collection<File> parseFilesRecursively(File file) {
+        if (isFileExcluded(file)) {
+            return Collections.emptyList();
+        }
+
+        if (file.isFile() && hasValidSuffix(file)) {
+            return Collections.singletonList(file);
+        }
+
+        String[] nestedFileNames = file.list();
+
+        if (nestedFileNames == null) {
+            return Collections.emptyList();
+        }
+
+        Collection<File> files = new ArrayList<>();
+
+        for (String fileName : nestedFileNames) {
+            files.addAll(parseFilesRecursively(new File(file, fileName)));
+        }
+
+        return files;
+    }
+
+    /**
+     * If an exclusion file is given, it is read in and all strings are saved in the set "excluded".
+     */
+    private HashSet<String> readExclusionFile() {
+        HashSet<String> excludedFileNames = new HashSet<>();
+        if (options.getExclusionFileName() != null) {
+            try {
+                BufferedReader reader = new BufferedReader(new FileReader(options.getExclusionFileName(), JPlagOptions.CHARSET));
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    excludedFileNames.add(line.trim());
+                }
+                reader.close();
+            } catch (IOException exception) {
+                System.out.println("Could not read exclusion file: " + exception.getMessage());
+            }
+
+            if (options.getVerbosity() == LONG) {
+                errorCollector.print(null, "Excluded files:\n");
+
+                for (String excludedFileName : excludedFileNames) {
+                    errorCollector.print(null, "  " + excludedFileName + "\n");
+                }
+            }
+        }
+        return excludedFileNames;
+    }
+}

+ 0 - 1
jplag/src/main/java/de/jplag/reporting/Report.java

@@ -449,7 +449,6 @@ public class Report { // Mostly legacy code with some minor improvements.
 
         if (options.getMaximumNumberOfComparisons() > 0) {
             htmlFile.println("<TR BGCOLOR=#aaaaff VALIGN=top><TD>" + msg.getString("Report.Matches_displayed") + ":</TD>" + "<TD>");
-            // TODO TS every instance of getComparisons must be replaced by get N in this class!
             htmlFile.println(options.getMaximumNumberOfComparisons() + " of " + result.getComparisons().size() + " ("
                     + msg.getString("Report.Treshold") + ": " + result.getOptions().getSimilarityThreshold() + "%)<br>");