diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileTreeWalker.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileTreeWalker.java new file mode 100644 index 0000000000000000000000000000000000000000..7729db4ef96d8fce05744917ebc82ece10b1db34 --- /dev/null +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/FileTreeWalker.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.test.packages.analyzer; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.logging.Logger; + +import com.oracle.truffle.r.test.packages.analyzer.detectors.DiffDetector; +import com.oracle.truffle.r.test.packages.analyzer.detectors.InstallationProblemDetector; +import com.oracle.truffle.r.test.packages.analyzer.detectors.RErrorDetector; +import com.oracle.truffle.r.test.packages.analyzer.detectors.RInternalErrorDetector; +import com.oracle.truffle.r.test.packages.analyzer.detectors.SegfaultDetector; +import com.oracle.truffle.r.test.packages.analyzer.detectors.UnsupportedSpecializationDetector; +import com.oracle.truffle.r.test.packages.analyzer.model.RPackage; +import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; +import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParseException; +import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParser; +import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParser.LogFile; + +public class FileTreeWalker { + private static final Logger LOGGER = Logger.getLogger(FileTreeWalker.class.getName()); + + private Collection<LogFileParseException> parseErrors; + + public Collection<RPackage> ftw(Path root, Date sinceDate, String glob) throws IOException { + + try (DirectoryStream<Path> stream = Files.newDirectoryStream(root, glob)) { + parseErrors = new ArrayList<>(); + Collection<RPackage> pkgs = new LinkedList<>(); + for (Path p : stream) { + if (Files.isDirectory(p)) { + Collection<RPackage> pkgVersions = visitPackageRoot(p, sinceDate); + pkgs.addAll(pkgVersions); + } + } + return pkgs; + } + } + + protected Collection<RPackage> visitPackageRoot(Path pkgRoot, Date sinceDate) throws IOException { + String pkgName = pkgRoot.getFileName().toString(); + + Collection<RPackage> pkgs = new LinkedList<>(); + try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgRoot)) { + for (Path p : stream) { + if (Files.isDirectory(p)) { + pkgs.add(visitPackageVersion(p, pkgName, sinceDate)); + } + } + } + return pkgs; + } + + protected RPackage visitPackageVersion(Path pkgVersionDir, String pkgName, Date sinceDate) { + String pkgVersion = pkgVersionDir.getFileName().toString(); + RPackage pkg = new RPackage(pkgName, pkgVersion); + LOGGER.info("Found package " + pkg); + + Collection<RPackageTestRun> runs = new LinkedList<>(); + try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgVersionDir)) { + for (Path p : stream) { + if (Files.isDirectory(p)) { + RPackageTestRun testRun = visitTestRun(p, pkg, sinceDate); + if (testRun != null) { + runs.add(testRun); + } + } + } + pkg.setTestRuns(runs); + } catch (IOException e) { + LOGGER.severe("Error while reading package root of \"" + pkgName + "\""); + } + + return pkg; + } + + protected RPackageTestRun visitTestRun(Path testRunDir, RPackage pkg, Date sinceDate) { + int testRun = Integer.parseInt(testRunDir.getFileName().toString()); + LOGGER.info("Visiting test run " + testRun + " of package " + pkg); + try { + RPackageTestRun pkgTestRun = new RPackageTestRun(pkg, testRun); + Path logFile = testRunDir.resolve(pkg.getName() + ".log"); + FileTime lastModifiedTime = Files.getLastModifiedTime(logFile); + if (isNewerThan(lastModifiedTime, sinceDate)) { + Collection<Problem> problems = parseLogFile(logFile, pkgTestRun); + pkgTestRun.setProblems(problems); + return pkgTestRun; + } else { + LOGGER.info(String.format("Skipping package test run %s because it is too old (%s must be newer than %s)", pkgTestRun, lastModifiedTime, sinceDate)); + } + } catch (IOException e) { + LOGGER.severe(String.format("Error while parsing test run %d of package \"%s-%s\": %s", testRun, + pkg.getName(), pkg.getVersion(), e.getMessage())); + } catch (LogFileParseException e) { + LOGGER.severe(String.format("Error while parsing test run %d of package \"%s-%s\": %s", testRun, + pkg.getName(), pkg.getVersion(), e.getMessage())); + parseErrors.add(e); + } + return null; + } + + private static boolean isNewerThan(FileTime lastModifiedTime, Date sinceDate) { + Date lastModDate = new Date(lastModifiedTime.toMillis()); + return sinceDate.compareTo(lastModDate) <= 0; + } + + private static Collection<Problem> parseLogFile(Path logFile, RPackageTestRun pkgTestRun) throws IOException { + LOGGER.info("Parsing log file " + logFile); + + LogFileParser lfParser = new LogFileParser(logFile, pkgTestRun); + lfParser.addDetector(LogFileParser.Token.BEGIN_SUGGESTS_INSTALL, InstallationProblemDetector.INSTANCE); + lfParser.addDetector(SegfaultDetector.INSTANCE); + lfParser.addDetector(RErrorDetector.INSTANCE); + lfParser.addDetector(UnsupportedSpecializationDetector.INSTANCE); + lfParser.addDetector(RInternalErrorDetector.INSTANCE); + lfParser.addTestResultDetector(DiffDetector.INSTANCE); + + LogFile parseLogFile = lfParser.parseLogFile(); + Collection<Problem> problems = parseLogFile.collectProblems(); + pkgTestRun.setSuccess(parseLogFile.isSuccess()); + + // log problems + LOGGER.fine("Overall test result: " + (pkgTestRun.isSuccess() ? "OK" : "FAILED")); + for (Problem problem : problems) { + LOGGER.fine(problem.toString()); + } + + return problems; + } + + public Collection<LogFileParseException> getParseErrors() { + return parseErrors; + } + +} diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/PTAMain.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/PTAMain.java index 8a0a14b27aa2f98b4fec61d494bb65a8831559f7..7342253b38bd39285155e7eb39b5ecf797a9033a 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/PTAMain.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/PTAMain.java @@ -23,11 +23,8 @@ package com.oracle.truffle.r.test.packages.analyzer; import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.attribute.FileTime; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -36,7 +33,6 @@ import java.util.Collection; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; @@ -47,18 +43,8 @@ import java.util.logging.SimpleFormatter; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.oracle.truffle.r.test.packages.analyzer.detectors.DiffDetector; -import com.oracle.truffle.r.test.packages.analyzer.detectors.InstallationProblemDetector; -import com.oracle.truffle.r.test.packages.analyzer.detectors.RErrorDetector; -import com.oracle.truffle.r.test.packages.analyzer.detectors.RInternalErrorDetector; -import com.oracle.truffle.r.test.packages.analyzer.detectors.SegfaultDetector; -import com.oracle.truffle.r.test.packages.analyzer.detectors.UnsupportedSpecializationDetector; import com.oracle.truffle.r.test.packages.analyzer.dump.HTMLDumper; import com.oracle.truffle.r.test.packages.analyzer.model.RPackage; -import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; -import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParseException; -import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParser; -import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParser.LogFile; /** * Main class of the package analysis tool.<br> @@ -108,6 +94,29 @@ public class PTAMain { ftw(Paths.get(remainingArgs[0]), outDir, sinceDate, parser.get("glob")); } + private static void ftw(Path root, Path outDir, Date sinceDate, String glob) { + HTMLDumper htmlDumper = new HTMLDumper(outDir); + + // fail early + try { + if (!htmlDumper.createAndCheckOutDir()) { + LOGGER.severe("Cannot write to output directory: " + outDir); + System.exit(1); + } + } catch (IOException e) { + LOGGER.severe(String.format("Cannot create output directory: %s ", e.getMessage())); + System.exit(1); + } + + try { + FileTreeWalker walker = new FileTreeWalker(); + Collection<RPackage> pkgs = walker.ftw(root, sinceDate, glob); + htmlDumper.dump(pkgs, walker.getParseErrors()); + } catch (IOException e) { + LOGGER.severe("Error while traversing package test directory: " + e.getMessage()); + } + } + private static final Pattern REL_SINCE_PATTERN = Pattern.compile("last(\\d+)(days?|weeks?|months?)"); private static Date parseSinceDate(OptionsParser parser) { @@ -176,121 +185,6 @@ public class PTAMain { private static final String LF = System.lineSeparator(); - private static void ftw(Path root, Path outDir, Date sinceDate, String glob) throws IOException { - // TODO FS checking - - HTMLDumper htmlDumper = new HTMLDumper(outDir); - - // fail early - try { - if (!htmlDumper.createAndCheckOutDir()) { - LOGGER.severe("Cannot write to output directory: " + outDir); - System.exit(1); - } - } catch (IOException e) { - LOGGER.severe(String.format("Cannot create output directory: %s ", e.getMessage())); - System.exit(1); - } - - try (DirectoryStream<Path> stream = Files.newDirectoryStream(root, glob)) { - Collection<RPackage> pkgs = new LinkedList<>(); - for (Path p : stream) { - if (Files.isDirectory(p)) { - Collection<RPackage> pkgVersions = visitPackageRoot(p, sinceDate); - pkgs.addAll(pkgVersions); - } - } - htmlDumper.dump(pkgs); - } - } - - private static Collection<RPackage> visitPackageRoot(Path pkgRoot, Date sinceDate) throws IOException { - String pkgName = pkgRoot.getFileName().toString(); - - Collection<RPackage> pkgs = new LinkedList<>(); - try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgRoot)) { - for (Path p : stream) { - if (Files.isDirectory(p)) { - pkgs.add(visitPackageVersion(p, pkgName, sinceDate)); - } - } - } - return pkgs; - } - - private static RPackage visitPackageVersion(Path pkgVersionDir, String pkgName, Date sinceDate) { - String pkgVersion = pkgVersionDir.getFileName().toString(); - RPackage pkg = new RPackage(pkgName, pkgVersion); - LOGGER.info("Found package " + pkg); - - Collection<RPackageTestRun> runs = new LinkedList<>(); - try (DirectoryStream<Path> stream = Files.newDirectoryStream(pkgVersionDir)) { - for (Path p : stream) { - if (Files.isDirectory(p)) { - RPackageTestRun testRun = visitTestRun(p, pkg, sinceDate); - if (testRun != null) { - runs.add(testRun); - } - } - } - pkg.setTestRuns(runs); - } catch (IOException e) { - LOGGER.severe("Error while reading package root of \"" + pkgName + "\""); - } - - return pkg; - } - - private static RPackageTestRun visitTestRun(Path testRunDir, RPackage pkg, Date sinceDate) { - int testRun = Integer.parseInt(testRunDir.getFileName().toString()); - LOGGER.info("Visiting test run " + testRun + " of package " + pkg); - try { - RPackageTestRun pkgTestRun = new RPackageTestRun(pkg, testRun); - Path logFile = testRunDir.resolve(pkg.getName() + ".log"); - FileTime lastModifiedTime = Files.getLastModifiedTime(logFile); - if (isNewerThan(lastModifiedTime, sinceDate)) { - Collection<Problem> problems = parseLogFile(logFile, pkgTestRun); - pkgTestRun.setProblems(problems); - return pkgTestRun; - } else { - LOGGER.info(String.format("Skipping package test run %s because it is too old (%s must be newer than %s)", pkgTestRun, lastModifiedTime, sinceDate)); - } - } catch (IOException | LogFileParseException e) { - LOGGER.severe(String.format("Error while parsing test run %d of package \"%s-%s\": %s", testRun, - pkg.getName(), pkg.getVersion(), e.getMessage())); - } - return null; - } - - private static boolean isNewerThan(FileTime lastModifiedTime, Date sinceDate) { - Date lastModDate = new Date(lastModifiedTime.toMillis()); - return sinceDate.compareTo(lastModDate) <= 0; - } - - private static Collection<Problem> parseLogFile(Path logFile, RPackageTestRun pkgTestRun) throws IOException { - LOGGER.info("Parsing log file " + logFile); - - LogFileParser lfParser = new LogFileParser(logFile, pkgTestRun); - lfParser.addDetector(LogFileParser.Token.BEGIN_SUGGESTS_INSTALL, InstallationProblemDetector.INSTANCE); - lfParser.addDetector(SegfaultDetector.INSTANCE); - lfParser.addDetector(RErrorDetector.INSTANCE); - lfParser.addDetector(UnsupportedSpecializationDetector.INSTANCE); - lfParser.addDetector(RInternalErrorDetector.INSTANCE); - lfParser.addTestResultDetector(DiffDetector.INSTANCE); - - LogFile parseLogFile = lfParser.parseLogFile(); - Collection<Problem> problems = parseLogFile.collectProblems(); - pkgTestRun.setSuccess(parseLogFile.isSuccess()); - - // log problems - LOGGER.fine("Overall test result: " + (pkgTestRun.isSuccess() ? "OK" : "FAILED")); - for (Problem problem : problems) { - LOGGER.fine(problem.toString()); - } - - return problems; - } - private static void printHelpAndExit() { StringBuilder sb = new StringBuilder(); sb.append("USAGE: ").append(PTAMain.class.getSimpleName()).append(" [OPTIONS] ROOT").append(LF); diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/detectors/RErrorDetector.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/detectors/RErrorDetector.java index 71c5764933983d98633dc5489463cbd4c3d0c1af..7b42a3b131f6b7c6a1419f5749f106b56ac01061 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/detectors/RErrorDetector.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/detectors/RErrorDetector.java @@ -37,7 +37,7 @@ public class RErrorDetector extends LineDetector { public static final RErrorDetector INSTANCE = new RErrorDetector(); - private static final Pattern PATTERN = Pattern.compile(".*\\wError(?<CALLSTR>.*)??: (?<MSG>.*)"); + private static final Pattern PATTERN = Pattern.compile("(.*\\s)?Error( in (?<CALLSTR>\\S*) )?: (?<MSG>.*)"); protected RErrorDetector() { } @@ -63,7 +63,7 @@ public class RErrorDetector extends LineDetector { if (matcher.matches()) { String callString = matcher.group("CALLSTR"); String message = matcher.group("MSG"); - if (message.trim().isEmpty()) { + if (message.trim().isEmpty() && it.hasNext()) { // message could be in the next line message = it.next(); ++i; @@ -94,9 +94,9 @@ public class RErrorDetector extends LineDetector { @Override public String getSummary() { if (callString != null) { - return "RError in '" + callString + "'"; + return "Error in " + callString + ""; } - return "RError"; + return "Error"; } @Override diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/AbstractDumper.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/AbstractDumper.java index 676c36a71f87df0d902746fe853b7c99ce392e4e..ff4ef7de99fc87760a21bca94bc92b85dbc588cc 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/AbstractDumper.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/AbstractDumper.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.test.packages.analyzer.dump; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -32,10 +31,11 @@ import java.util.stream.Collectors; import com.oracle.truffle.r.test.packages.analyzer.Problem; import com.oracle.truffle.r.test.packages.analyzer.model.RPackage; import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; +import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParseException; public abstract class AbstractDumper { - public abstract void dump(Collection<RPackage> problems); + public abstract void dump(Collection<RPackage> problems, Collection<LogFileParseException> collection); protected Map<Class<? extends Problem>, List<Problem>> groupByType(Collection<Problem> problems) { return problems.stream().collect(Collectors.groupingBy(p -> p.getClass())); diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/HTMLDumper.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/HTMLDumper.java index 853bb07cbb65c51d3c048bf643f065a919e9a4b3..fa861b8245470de76f660af89381765ff897a255 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/HTMLDumper.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/dump/HTMLDumper.java @@ -43,6 +43,7 @@ import com.oracle.truffle.r.test.packages.analyzer.Problem; import com.oracle.truffle.r.test.packages.analyzer.dump.HTMLBuilder.Tag; import com.oracle.truffle.r.test.packages.analyzer.model.RPackage; import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; +import com.oracle.truffle.r.test.packages.analyzer.parser.LogFileParseException; public class HTMLDumper extends AbstractDumper { @@ -65,16 +66,16 @@ public class HTMLDumper extends AbstractDumper { } @Override - public void dump(Collection<RPackage> problems) { + public void dump(Collection<RPackage> problems, Collection<LogFileParseException> parseErrors) { try { createAndCheckOutDir(); - dumpIndexFile(problems); + dumpIndexFile(problems, parseErrors); } catch (IOException e) { e.printStackTrace(); } } - private void dumpIndexFile(Collection<RPackage> problems) { + private void dumpIndexFile(Collection<RPackage> problems, Collection<LogFileParseException> parseErrors) { Path indexFile = destDir.resolve("index.html"); try (BufferedWriter bw = Files.newBufferedWriter(indexFile, CREATE, TRUNCATE_EXISTING, WRITE)) { @@ -86,13 +87,14 @@ public class HTMLDumper extends AbstractDumper { Tag errorDistributionTable = generateTypeDistributionTable(builder, groupByType(allProblems)); Tag pkgDistributionTable = generateTestRunDistributionTable(builder, groupByTestRuns(allTestRuns, allProblems)); Tag distrinctProblemDistributionTable = generateDistinctProblemDistribution(builder, groupByProblemContent(allProblems)); + Tag parseErrorsList = generateParseErrorsList(builder, parseErrors); builder.html(builder.head(builder.title(TITLE)), builder.body( - builder.h1(TITLE), - builder.p("Numer of analyzer package test runs: " + allTestRuns.size()), + builder.h1(TITLE), builder.p("Numer of analyzed package test runs: " + allTestRuns.size()), builder.h2("Distribution by Problem Type"), errorDistributionTable, builder.h2("Distribution by Package Test Run"), pkgDistributionTable, - builder.h2("Distinct Problem Distribution"), distrinctProblemDistributionTable)); + builder.h2("Distinct Problem Distribution"), distrinctProblemDistributionTable, + builder.h2("Failed Analysis Runs"), parseErrorsList)); builder.dump(); } catch (IOException e) { e.printStackTrace(); @@ -212,4 +214,20 @@ public class HTMLDumper extends AbstractDumper { return table; } + private static Tag generateParseErrorsList(HTMLBuilder builder, Collection<LogFileParseException> parseErrors) { + + Tag table = builder.table(builder.tr( + builder.th("Package Test Run"), + builder.th("Location"), + builder.th("Message"))); + + for (LogFileParseException e : parseErrors) { + table.addChild(builder.tr( + builder.td(e.getTestRun().toString()), + builder.td(e.getLocation().toString()), + builder.td(e.getMessage()))); + } + return table; + } + } diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/DiffParser.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/DiffParser.java index 95739783f6451be275c17239e29885a370cc3d81..7c6a3ab3ec13100b4bf7753afbd8fe3237ce6b96 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/DiffParser.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/DiffParser.java @@ -48,7 +48,7 @@ public class DiffParser { * group("CMD") = command<br> * </p> */ - static final Pattern CHANGE_CMD_PATTERN = Pattern.compile("(\\d+)(,(\\d+))?(?<CMD>a|c|d)(\\d+)(,(\\d+))?"); + public static final Pattern CHANGE_CMD_PATTERN = Pattern.compile("(\\d+)(,(\\d+))?(?<CMD>a|c|d)(\\d+)(,(\\d+))?"); protected DiffParser(LogFileParser parent) { this.parent = parent; @@ -90,7 +90,7 @@ public class DiffParser { break; } default: - throw new LogFileParseException("Unknown diff command: "); + throw parent.parseError("Unknown diff command: "); } } else { // no more diff chunks; exit loop @@ -122,7 +122,7 @@ public class DiffParser { if (matcher.matches()) { String cmdStr = matcher.group("CMD"); if (cmdStr.length() != 1) { - throw new LogFileParseException("Invalid diff change command: " + cmdStr); + throw parent.parseError("Invalid diff change command: " + cmdStr); } char cmd = cmdStr.charAt(0); @@ -134,7 +134,7 @@ public class DiffParser { return new ChangeCommand(atoi(lFromStr), atoi(lToStr), cmd, atoi(rFromStr), atoi(rToStr)); } - throw new LogFileParseException("Invalid diff change command: " + parent.getCurLine().text); + throw parent.parseError("Invalid diff change command: " + parent.getCurLine().text); } private static int atoi(String rToStr) { @@ -224,7 +224,7 @@ public class DiffParser { public final int rFrom; public final int rTo; - protected ChangeCommand(int lFrom, int lTo, char cmd, int rFrom, int rTo) { + public ChangeCommand(int lFrom, int lTo, char cmd, int rFrom, int rTo) { this.lFrom = lFrom; this.lTo = lTo; this.cmd = cmd; diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParseException.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParseException.java index ac9740109bb06bc0f6b9c7419eb8b7fd998ba537..c76f3756a2ed2d98f24c1c3ee933673c072e3193 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParseException.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParseException.java @@ -22,11 +22,29 @@ */ package com.oracle.truffle.r.test.packages.analyzer.parser; +import java.util.Objects; + +import com.oracle.truffle.r.test.packages.analyzer.Location; +import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; + @SuppressWarnings("serial") public class LogFileParseException extends RuntimeException { - protected LogFileParseException(String message) { + private final RPackageTestRun testRun; + private final Location location; + + protected LogFileParseException(String message, RPackageTestRun testRun, Location location) { super(message); + this.testRun = Objects.requireNonNull(testRun); + this.location = Objects.requireNonNull(location); + } + + public RPackageTestRun getTestRun() { + return testRun; + } + + public Location getLocation() { + return location; } } diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParser.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParser.java index 4f7a2580548c497d97a2979009222ff5b2c6690c..64915677edad06704543e27e73b8fb06d5754bfd 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParser.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/LogFileParser.java @@ -113,7 +113,7 @@ public class LogFileParser { void expectEOF() throws IOException { consumeLine(); if (!isEOF(curLine)) { - throw new LogFileParseException("Expected end of file but was " + curLine.text); + throw new LogFileParseException("Expected end of file but was " + curLine.text, pkg, getCurrentLocation()); } } @@ -153,14 +153,14 @@ public class LogFileParser { } checkResults.setSuccess(false); } else { - throw new LogFileParseException("Unexpected checking message: " + curLine.text); + throw parseError("Unexpected checking message: " + curLine.text); } expect(Token.END_CHECKING); return checkResults; } - private Location getCurrentLocation() { + Location getCurrentLocation() { return new Location(logFile.path, curLine.lineNr); } @@ -171,7 +171,7 @@ public class LogFileParser { String mode = trim(curLine.text).substring(Token.BEGIN_INSTALL_TEST.linePrefix.length()); if (!("FastR".equals(mode) || "GnuR".equals(mode))) { - throw new LogFileParseException("Invalid mode: " + mode); + throw parseError("Invalid mode: " + mode); } Section installationTask = parseInstallationTask(); @@ -301,13 +301,13 @@ public class LogFileParser { return pkg.getPackage().getName(); } - private static boolean parseStatus(String substring) { + private boolean parseStatus(String substring) { if (Token.OK.linePrefix.equals(substring.trim())) { return true; } else if (Token.FAILED.linePrefix.equals(substring.trim())) { return false; } - throw new LogFileParseException("Unexpected status: " + substring); + throw parseError("Unexpected status: " + substring); } private Section parseInstallSuggests() throws IOException { @@ -409,10 +409,14 @@ public class LogFileParser { void expect(String linePrefix) throws IOException { consumeLine(); if (isEOF(curLine) || !trim(curLine.text).startsWith(linePrefix)) { - throw new LogFileParseException("Unexpected line " + (curLine.lineNr + 1) + " (expected \"" + linePrefix + "\" but was \"" + (isEOF(curLine) ? "<EOF>" : curLine.text) + "\""); + throw parseError("Unexpected line " + (curLine.lineNr + 1) + " (expected \"" + linePrefix + "\" but was \"" + (isEOF(curLine) ? "<EOF>" : curLine.text) + "\""); } } + LogFileParseException parseError(String message) { + throw new LogFileParseException(message, pkg, getCurrentLocation()); + } + void consumeLine() throws IOException { curLine = la; // skip empty lines diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/PatternTest.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/PatternTest.java similarity index 96% rename from com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/PatternTest.java rename to com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/PatternTest.java index f4c8cce61213940de30211bc41871767ff86b1f0..3084ee7d470bb57e8be9641eac558a0c21eaff4f 100644 --- a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/parser/PatternTest.java +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/PatternTest.java @@ -20,13 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.test.packages.analyzer.parser; +package com.oracle.truffle.r.test.packages.analyzer.test; import java.util.regex.Matcher; import org.junit.Assert; import org.junit.Test; +import com.oracle.truffle.r.test.packages.analyzer.parser.DiffParser; import com.oracle.truffle.r.test.packages.analyzer.parser.DiffParser.ChangeCommand; public class PatternTest { diff --git a/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/RErrorDetectorTest.java b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/RErrorDetectorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cf432fc3f5c48399a45195a7b0770aa119f03989 --- /dev/null +++ b/com.oracle.truffle.r.test.packages.analyzer/src/com/oracle/truffle/r/test/packages/analyzer/test/RErrorDetectorTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.test.packages.analyzer.test; + +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.Assert; +import org.junit.Test; + +import com.oracle.truffle.r.test.packages.analyzer.Location; +import com.oracle.truffle.r.test.packages.analyzer.Problem; +import com.oracle.truffle.r.test.packages.analyzer.detectors.RErrorDetector; +import com.oracle.truffle.r.test.packages.analyzer.model.RPackage; +import com.oracle.truffle.r.test.packages.analyzer.model.RPackageTestRun; + +public class RErrorDetectorTest { + + private static final RPackage pkg; + private static final RPackageTestRun pkgTestRun; + + static { + pkg = new RPackage("fastr", "0.27"); + pkg.setLocation(Paths.get("fastr")); + pkgTestRun = new RPackageTestRun(pkg, 1); + } + + @Test + public void testMultiLine() { + List<String> lines = Arrays.asList(new String[]{"Error in check(options) : ", + "ERROR: installing Rd objects failed for package ‘RUnit’"}); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error in check(options)", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("ERROR: installing Rd objects failed for package ‘RUnit’", findFirst.orElse(null).getDetails().trim()); + + } + + @Test + public void testSingleLine0() { + List<String> lines = Collections.singletonList("Error in check(options) : invalid value for 'label' "); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error in check(options)", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label'", findFirst.orElse(null).getDetails().trim()); + + } + + @Test + public void testSingleLine1() { + List<String> lines = Collections.singletonList("Error in check : invalid value for 'label' "); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error in check", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label'", findFirst.orElse(null).getDetails().trim()); + + } + + @Test + public void testSingleLineMultipleColon() { + List<String> lines = Collections.singletonList("Error in check(options) : invalid value for 'label' : "); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error in check(options)", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label' :", findFirst.orElse(null).getDetails().trim()); + + } + + @Test + public void testSingleLineWithoutCallstring0() { + List<String> lines = Collections.singletonList("Error: invalid value for 'label' "); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label'", findFirst.orElse(null).getDetails().trim()); + + } + + @Test + public void testSingleLineWithoutCallstring1() { + List<String> lines = Collections.singletonList("Error: invalid value for 'label' : "); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label' :", findFirst.orElse(null).getDetails().trim()); + } + + @Test + public void testRInternalError0() { + List<String> lines = Collections.singletonList("RInternalError: invalid value for 'label'"); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(0, detect.size()); + } + + @Test + public void testRInternalError1() { + List<String> lines = Collections.singletonList("> RInternalError: invalid value for 'label'"); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(0, detect.size()); + } + + @Test + public void testRInternalError2() { + List<String> lines = Collections.singletonList(" RInternalError: invalid value for 'label'"); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(0, detect.size()); + } + + @Test + public void testWithLinePrefix() { + List<String> lines = Collections.singletonList("> Error: invalid value for 'label'"); + + Collection<Problem> detect = RErrorDetector.INSTANCE.detect(pkgTestRun, loc(), lines); + Assert.assertEquals(1, detect.size()); + + Optional<Problem> findFirst = detect.stream().findFirst(); + Assert.assertEquals("Error", findFirst.orElse(null).getSummary().trim()); + Assert.assertEquals("invalid value for 'label'", findFirst.orElse(null).getDetails().trim()); + } + + private static Location loc() { + return new Location(pkg.getLocation(), 0); + } + +}