Procházet zdrojové kódy

Overhaul how errors are reported and how and when their messages are printed.

Timur Sağlam před 4 roky
rodič
revize
2c41ef8952

+ 1 - 1
jplag.frontend.chars/src/main/java/de/jplag/chars/Parser.java

@@ -16,7 +16,7 @@ public class Parser extends AbstractParser implements TokenConstants {
 		struct = new TokenList();
 		errors = 0;
 		for (int i = 0; i < files.length; i++) {
-			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			getProgram().print(null, "Parsing file " + files[i]);
 			if (!parseFile(dir, files[i]))
 				errors++;
 			struct.addToken(new CharToken(FILE_END, files[i], this));

+ 1 - 1
jplag.frontend.cpp/src/main/java/de/jplag/cpp/Scanner.java

@@ -16,7 +16,7 @@ public class Scanner extends AbstractParser implements CPPTokenConstants {
 		CPPScanner scanner = null;// will be initialized in Method scanFile
 		for (int i = 0; i < files.length; i++) {
 			actFile = files[i];
-		    getProgram().print(null, "Scanning file " + files[i] + "\n");
+		    getProgram().print(null, "Scanning file " + files[i]);
 			if (!CPPScanner.scanFile(dir, files[i], scanner, this))
 				errors++;
 			struct.addToken(new CPPToken(FILE_END, actFile, 1));

+ 2 - 2
jplag.frontend.cpp/src/main/javacc/CPP.jj

@@ -38,10 +38,10 @@ public class CPPScanner implements CPPTokenConstants {
         try {
               scanner.scan();
         } catch (ParseException e) {
-              scannerX.getProgram().addError("  Parsing Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
+              scannerX.getProgram().addError("  Parsing Error in '" + fileName + "':\n  " + e.getMessage());
               return false;
         } catch (TokenMgrError e) {
-              scannerX.getProgram().addError("  Scanning Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
+              scannerX.getProgram().addError("  Scanning Error in '" + fileName + "':\n  " + e.getMessage());
               return false;
         }
         return true;

+ 1 - 2
jplag.frontend.csharp-1.2/src/main/java/de/jplag/csharp/Parser.java

@@ -19,7 +19,6 @@ public class Parser extends AbstractParser implements CSharpTokenConstants {
 		struct = new TokenList();
 		errors = 0;
 		for (int i = 0; i < files.length; i++) {
-			//			getProgram().print(null, "Parsing file " + files[i] + "\n");
 			if (!parseFile(dir, files[i]))
 				errors++;
 			struct.addToken(new CSharpToken(FILE_END, files[i], -1, -1, -1));
@@ -47,7 +46,7 @@ public class Parser extends AbstractParser implements CSharpTokenConstants {
 			// close file
 			fis.close();
 		} catch (Exception e) {
-			getProgram().addError("  Parsing Error in '" + file + "':\n  " + e.toString() + "\n");
+			getProgram().addError("  Parsing Error in '" + file + "':\n  " + e.toString());
 			return false;
 		}
 		return true;

+ 3 - 3
jplag.frontend.java-1.1exp/src/main/java/de/jplag/javax/Parser.java

@@ -17,15 +17,15 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 		// in method parseFile(...)
 		for (int i = 0; i < files.length; i++) {
 			actFile = files[i];
-			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			getProgram().print(null, "Parsing file " + files[i]);
 			if (!JavaParser.parseFile(dir, files[i], parser, this))
 				errors++;
 			struct.addToken(new JavaToken(FILE_END, actFile, 0));
 		}
 		if (errors == 0)
-			program.print(null, "OK\n");
+			program.print(null, "OK");
 		else
-			program.print(null, errors + " ERRORS\n");
+			program.print(null, errors + " ERRORS");
 		this.parseEnd();
 		return struct;
 	}

+ 2 - 2
jplag.frontend.java-1.1exp/src/main/javacc/Java1.1.jj

@@ -49,11 +49,11 @@ public class JavaParser implements JavaTokenConstants {
       parser.CompilationUnit();
     } catch (ParseException e) {
       parserX.getProgram().addError("  Parsing Error in '" + fileName + "':\n  "
-                + e.getMessage() + "\n");
+                + e.getMessage());
       return false;
     } catch (TokenMgrError e) {
       parserX.getProgram().addError("  Scanning Error in '" + fileName
-      		+ "':\n  " + e.getMessage() + "\n");
+      		+ "':\n  " + e.getMessage());
       return true; //false;		// TODO: Why has this been manually set to true?
     }
     return true;

+ 2 - 2
jplag.frontend.java-1.2/src/main/java/de/jplag/java/Parser.java

@@ -19,7 +19,7 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 		struct = new TokenList();
 		errors = 0;
 		for (int i = 0; i < files.length; i++) {
-			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			getProgram().print(null, "Parsing file " + files[i]);
 			if (!parseFile(dir, files[i]))
 				errors++;
 			System.gc();//Emeric
@@ -54,7 +54,7 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 			getProgram().addError(
 					"  Parsing Error in '" + file + "':\n" + "  Parse error at line "
 							+ (inputState != null ? "" + inputState.getLine() : "UNKNOWN") + ", column "
-							+ (inputState != null ? "" + inputState.tokColumn : "UNKNOWN") + ": " + e.getMessage() + "\n");
+							+ (inputState != null ? "" + inputState.tokColumn : "UNKNOWN") + ": " + e.getMessage());
 			return false;
 		}
 

+ 1 - 1
jplag.frontend.java-1.5/src/main/java/de/jplag/java15/Parser.java

@@ -25,7 +25,7 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 
 		for (int i = 0; i < files.length; i++) {
 			actFile = files[i];
-			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			getProgram().print(null, "Parsing file " + files[i]);
 			if (!JavaParser.parseFile(dir, files[i], parser, this))
 				errors++;
 

+ 2 - 2
jplag.frontend.java-1.7/src/main/java/de/jplag/java17/Parser.java

@@ -26,7 +26,7 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 		struct = new TokenList();
 		errors = 0;
 		for (int i = 0; i < files.length; i++) {
-			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			getProgram().print(null, "Parsing file " + files[i]);
 			if (!parseFile(dir, files[i]))
 				errors++;
 			System.gc();//Emeric
@@ -62,7 +62,7 @@ public class Parser extends AbstractParser implements JavaTokenConstants {
 			}
 
 		} catch (IOException e) {
-			getProgram().addError("Parsing Error in '" + file + "':\n" + e.getMessage() + "\n");
+			getProgram().addError("Parsing Error in '" + file + "':\n" + e.getMessage());
 			return false;
 		}
 

+ 1 - 1
jplag.frontend.java-1.9/src/main/java/de/jplag/java19/JavacAdapter.java

@@ -49,7 +49,7 @@ public class JavacAdapter {
         int errors = 0;
         for (Diagnostic<?> diagItem : diagListen.getDiagnostics()) {
             if (diagItem.getKind() == javax.tools.Diagnostic.Kind.ERROR) {
-                System.out.println(diagItem); // TODO TS: Implement proper logging.
+                parser.getProgram().addError(diagItem.toString());
                 errors++;
             }
         }

+ 2 - 2
jplag.frontend.python-3/src/main/java/de/jplag/python3/Parser.java

@@ -27,7 +27,7 @@ public class Parser extends AbstractParser implements Python3TokenConstants {
         struct = new TokenList();
         errors = 0;
         for (int i = 0; i < files.length; i++) {
-            getProgram().print(null, "Parsing file " + files[i] + "\n");
+            getProgram().print(null, "Parsing file " + files[i]);
             if (!parseFile(dir, files[i])) {
                 errors++;
             }
@@ -64,7 +64,7 @@ public class Parser extends AbstractParser implements Python3TokenConstants {
             }
 
         } catch (IOException e) {
-            getProgram().addError("Parsing Error in '" + file + "':\n" + e.getMessage() + "\n");
+            getProgram().addError("Parsing Error in '" + file + "':\n" + e.getMessage());
             return false;
         }
 

+ 1 - 1
jplag.frontend.scheme/src/main/java/de/jplag/scheme/Parser.java

@@ -17,7 +17,7 @@ public class Parser extends AbstractParser implements SchemeTokenConstants {
 		// in method parseFile(...)
 		for (int i = 0; i < files.length; i++) {
 			actFile = files[i];
-		    getProgram().print(null, "Parsing file " + files[i] + "\n");
+		    getProgram().print(null, "Parsing file " + files[i]);
 			if (!SchemeParser.parseFile(dir, files[i], parser, this))
 				errors++;
 			struct.addToken(new SchemeToken(FILE_END, actFile, 1));

+ 1 - 1
jplag.frontend.text/src/main/java/de/jplag/text/Parser.java

@@ -54,7 +54,7 @@ public class Parser extends AbstractParser implements TokenConstants {
 		struct = new TokenList();
 		errors = 0;
 		for (int i = 0; i < files.length; i++) {
-			getProgram().print("", "Parsing file " + files[i] + "\n");
+			getProgram().print("", "Parsing file " + files[i]);
 			if (!parseFile(dir, files[i]))
 				errors++;
 			struct.addToken(new TextToken(FILE_END, files[i], this));

+ 17 - 5
jplag/src/main/java/de/jplag/ErrorCollector.java

@@ -8,6 +8,10 @@ import java.util.List;
 import de.jplag.options.JPlagOptions;
 import de.jplag.options.Verbosity;
 
+/**
+ * Error collector class that collects errors but also allows printing the collected errors.
+ * @author Timur Saglam
+ */
 public class ErrorCollector implements ErrorConsumer { // TODO TS should be eventually replaced with a true logger/logging manager
 
     private final List<String> collectedErrors; // List of errors that occurred during the execution of the program.
@@ -22,8 +26,8 @@ public class ErrorCollector implements ErrorConsumer { // TODO TS should be even
 
     @Override
     public void addError(String errorMessage) {
-        collectedErrors.add("[" + currentSubmissionName + "]\n" + errorMessage);
-        print(null, currentSubmissionName + ": " + errorMessage);
+        collectedErrors.add("[" + currentSubmissionName + "] " + errorMessage);
+        print(null, "\t" + errorMessage);
     }
 
     @Override
@@ -33,18 +37,19 @@ public class ErrorCollector implements ErrorConsumer { // TODO TS should be even
         }
         Verbosity verbosity = options.getVerbosity();
         if (message != null) {
-            System.out.print(message);
+            System.out.println(message);
         }
         if (longMessage != null && verbosity == LONG) {
-            System.out.print(longMessage);
+            System.out.println(longMessage);
         }
     }
 
     /**
      * Print all collected errors messages in a list-like fashion.
      */
-    public void printErrors() {
+    public void printCollectedErrors() {
         StringBuilder errorReport = new StringBuilder();
+        System.out.println("The following errors occured: ");
         for (String message : collectedErrors) {
             errorReport.append(message);
             errorReport.append('\n');
@@ -60,4 +65,11 @@ public class ErrorCollector implements ErrorConsumer { // TODO TS should be even
     public void setCurrentSubmissionName(String currentSubmissionName) {
         this.currentSubmissionName = currentSubmissionName;
     }
+
+    /**
+     * @return true if there is at least one error.
+     */
+    public boolean hasErrors() {
+        return !collectedErrors.isEmpty();
+    }
 }

+ 4 - 5
jplag/src/main/java/de/jplag/JPlag.java

@@ -51,16 +51,15 @@ public class JPlag {
             coreAlgorithm.createHashes(submissionSet.getBaseCode().getTokenList(), options.getMinimumTokenMatch(), true);
         }
 
-        int submCount = submissionSet.numberOfSubmissions();
-        if (submCount < 2) {
-            errorCollector.printErrors();
-            throw new ExitException("Not enough valid submissions! (found " + submCount + " valid submissions)",
+        int submissionCount = submissionSet.numberOfSubmissions();
+        if (submissionCount < 2) {
+            throw new ExitException("Not enough valid submissions! (found " + submissionCount + " valid submissions)",
                     ExitException.NOT_ENOUGH_SUBMISSIONS_ERROR);
         }
 
         // Compare valid submissions.
         JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet);
-        System.out.println("Total time for comparing submissions: " + TimeUtil.formatDuration(result.getDuration()));
+        errorCollector.print("\nTotal time for comparing submissions: " + TimeUtil.formatDuration(result.getDuration()), null);
         return result;
     }
 

+ 2 - 2
jplag/src/main/java/de/jplag/Submission.java

@@ -153,7 +153,7 @@ public class Submission implements Comparable<Submission> {
      */
     public boolean parse(boolean debugParser) {
         if (files == null || files.size() == 0) {
-            errorCollector.print("ERROR: nothing to parse for submission \"" + name + "\"\n", null);
+            errorCollector.print("ERROR: nothing to parse for submission \"" + name, null);
             return false;
         }
 
@@ -162,7 +162,7 @@ public class Submission implements Comparable<Submission> {
         tokenList = language.parse(submissionRoot, relativeFilePaths);
         if (!language.hasErrors()) {
             if (tokenList.size() < 3) {
-                errorCollector.print("Submission \"" + name + "\" is too short!\n", null);
+                errorCollector.print("Submission \"" + name + "\" is too short!", null);
                 tokenList = null;
                 hasErrors = true; // invalidate submission
                 return false;

+ 41 - 31
jplag/src/main/java/de/jplag/SubmissionSet.java

@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
 import de.jplag.options.JPlagOptions;
 
 /**
- * Collection of all submissions and their basecode if it exists. Parses all allSubmissions upon creation.
+ * Collection of all submissions and their basecode if it exists. Parses all submissions upon creation.
  */
 public class SubmissionSet {
     /**
@@ -31,17 +31,17 @@ public class SubmissionSet {
     private String currentSubmissionName;
 
     /**
-     * @param allSubmissions Submissions to check for plagiarism.
+     * @param submissions Submissions to check for plagiarism.
      * @param baseCode Base code submission if it exists.
      */
-    public SubmissionSet(List<Submission> allSubmissions, Optional<Submission> baseCode, ErrorCollector errorCollector, JPlagOptions options)
+    public SubmissionSet(List<Submission> submissions, Optional<Submission> baseCode, ErrorCollector errorCollector, JPlagOptions options)
             throws ExitException {
-        this.allSubmissions = allSubmissions;
+        this.allSubmissions = submissions;
         this.baseCodeSubmission = baseCode;
         this.errorCollector = errorCollector;
         this.options = options;
         parseAllSubmissions();
-        submissions = filterValidSubmissions();
+        this.submissions = filterValidSubmissions();
         invalidSubmissions = filterInvalidSubmissions();
     }
 
@@ -73,13 +73,17 @@ public class SubmissionSet {
     }
 
     /**
-     * Obtain the submissions.
+     * Obtain the valid submissions.
      * @note Changes in the list are reflected in this instance.
      */
     public List<Submission> getSubmissions() {
         return submissions;
     }
 
+    /**
+     * Obtain the invalid submissions.
+     * @note Changes in the list are reflected in this instance.
+     */
     public List<Submission> getInvalidSubmissions() {
         return invalidSubmissions;
     }
@@ -104,6 +108,9 @@ public class SubmissionSet {
             e.printStackTrace();
             throw new ExitException("Unknown exception during parsing of " + "submission \"" + currentSubmissionName + "\"");
         }
+        if (errorCollector.hasErrors()) {
+            errorCollector.printCollectedErrors();
+        }
     }
 
     /**
@@ -111,17 +118,17 @@ public class SubmissionSet {
      */
     private void parseBaseCodeSubmission(Submission baseCode) throws ExitException {
         long startTime = System.currentTimeMillis();
-        errorCollector.print("----- Parsing basecode submission: " + baseCode.getName() + "\n", null);
+        errorCollector.print("----- Parsing basecode submission: " + baseCode.getName(), null);
         if (!baseCode.parse(options.isDebugParser())) {
-            errorCollector.printErrors();
+            errorCollector.printCollectedErrors();
             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");
+            throw new ExitException("Basecode submission contains fewer tokens than minimum match length allows!");
         }
-        errorCollector.print("\nBasecode submission parsed!\n", null);
+        errorCollector.print("Basecode submission parsed!", null);
         long duration = System.currentTimeMillis() - startTime;
-        errorCollector.print("\n", "\nTime for parsing Basecode: " + TimeUtil.formatDuration(duration) + "\n");
+        errorCollector.print(null, "Time for parsing Basecode: " + TimeUtil.formatDuration(duration));
 
     }
 
@@ -134,16 +141,13 @@ public class SubmissionSet {
             return;
         }
 
-        int count = 0;
-
         long startTime = System.currentTimeMillis();
 
-        int tooSmallSubmissions = 0;
+        int tooShort = 0;
         for (Submission submission : submissions) {
             boolean ok;
-            boolean removed = false;
 
-            errorCollector.print(null, "------ Parsing submission: " + submission.getName() + "\n");
+            errorCollector.print(null, "------ Parsing submission: " + submission.getName());
             currentSubmissionName = submission.getName();
             errorCollector.setCurrentSubmissionName(currentSubmissionName);
 
@@ -152,33 +156,39 @@ public class SubmissionSet {
             }
 
             if (submission.getTokenList() != null && submission.getNumberOfTokens() < options.getMinimumTokenMatch()) {
-                errorCollector.addError("Submission contains fewer tokens than minimum match length allows!\n");
+                errorCollector.addError("Submission contains fewer tokens than minimum match length allows!");
                 submission.setTokenList(null);
-                tooSmallSubmissions++;
-                removed = true;
+                tooShort++;
+                ok = false;
                 submission.markAsErroneous();
             }
 
-            if (ok && !removed) {
-                errorCollector.print(null, "OK\n");
+            if (ok) {
+                errorCollector.print(null, "OK");
             } else {
-                errorCollector.print(null, "ERROR -> Submission removed\n");
+                errorCollector.print(null, "ERROR -> Submission removed");
             }
         }
 
-        int validSubmissions = submissions.size() - errors - tooSmallSubmissions;
-        errorCollector.print(validSubmissions + " allSubmissions parsed successfully!", null);
-        errorCollector.print(errors + " parser error" + (errors != 1 ? "s!\n" : "!\n"), null);
+        int validSubmissions = submissions.size() - errors - tooShort;
+        errorCollector.print(validSubmissions + " submissions parsed successfully!", null);
+        errorCollector.print(errors + " parser error" + (errors != 1 ? "s!" : "!") + "", null);
+        errorCollector.print(tooShort + " too short submission" + (tooShort != 1 ? "s!" : "!") + "", null);
+        printDetails(submissions, startTime, tooShort);
+        errorCollector.print("", null); // new line
+    }
 
-        if (tooSmallSubmissions == 1) {
-            errorCollector.print(null, tooSmallSubmissions + " submission is not valid because it contains fewer tokens than minimum match length allows.\n");
-        } else if (tooSmallSubmissions > 1) {
-            errorCollector.print(null, tooSmallSubmissions + " submissions are not valid because they contain fewer tokens than minimum match length allows.\n");
+    private void printDetails(List<Submission> submissions, long startTime, int tooShort) {
+        if (tooShort == 1) {
+            errorCollector.print(null, tooShort + " submission is not valid because it contains fewer tokens than minimum match length allows.");
+        } else if (tooShort > 1) {
+            errorCollector.print(null, tooShort + " submissions are not valid because they contain fewer tokens than minimum match length allows.");
         }
 
         long duration = System.currentTimeMillis() - startTime;
-        errorCollector.print("\n\n", "\nTotal time for parsing: " + TimeUtil.formatDuration(duration) + "\n" + "Time per parsed submission: "
-                + (count > 0 ? (duration / count) : "n/a") + " msec\n");
+        String timePerSubmission = submissions.size() > 0 ? Long.toString(duration / submissions.size()) : "n/a";
+        errorCollector.print(null, "Total time for parsing: " + TimeUtil.formatDuration(duration));
+        errorCollector.print(null, "Time per parsed submission: " + timePerSubmission + " msec");
     }
 
 }

+ 2 - 2
jplag/src/main/java/de/jplag/SubmissionSetBuilder.java

@@ -178,10 +178,10 @@ public class SubmissionSetBuilder {
             }
 
             if (options.getVerbosity() == LONG) {
-                errorCollector.print(null, "Excluded files:\n");
+                errorCollector.print(null, "Excluded files:");
 
                 for (String excludedFileName : excludedFileNames) {
-                    errorCollector.print(null, "  " + excludedFileName + "\n");
+                    errorCollector.print(null, "  " + excludedFileName);
                 }
             }
         }

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

@@ -54,7 +54,7 @@ public class Report { // Mostly legacy code with some minor improvements.
 
     public void writeResult(JPlagResult result) throws ExitException {
         this.result = result;
-        System.out.println("Writing report...");
+        System.out.println("\nWriting report...");
         writeIndex();
         copyStaticFiles();
         writeMatches(result.getComparisons(options.getMaximumNumberOfComparisons()));