/* * Copyright (C) 2014-2015 Daniel Dietsch (dietsch@informatik.uni-freiburg.de) * Copyright (C) 2014-2015 Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * Copyright (C) 2015 University of Freiburg * * This file is part of the ULTIMATE UnitTest Library. * * The ULTIMATE UnitTest Library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ULTIMATE UnitTest Library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ULTIMATE UnitTest Library. If not, see . * * Additional permission under GNU GPL version 3 section 7: * If you modify the ULTIMATE UnitTest Library, or any covered work, by linking * or combining it with Eclipse RCP (or a modified version of Eclipse RCP), * containing parts covered by the terms of the Eclipse Public License, the * licensors of the ULTIMATE UnitTest Library grant you additional permission * to convey the resulting work. */ package de.uni_freiburg.informatik.ultimate.test.util; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.function.Predicate; import java.util.stream.Stream; import de.uni_freiburg.informatik.ultimate.core.model.results.IResult; import de.uni_freiburg.informatik.ultimate.core.model.services.ILogger; import de.uni_freiburg.informatik.ultimate.core.model.services.IResultService; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.test.decider.overallresult.SafetyCheckerOverallResult; import de.uni_freiburg.informatik.ultimate.test.decider.overallresult.TerminationAnalysisOverallResult; import de.uni_freiburg.informatik.ultimate.test.reporting.INonIncrementalLog; import de.uni_freiburg.informatik.ultimate.test.reporting.ITestLogfile; import de.uni_freiburg.informatik.ultimate.util.CoreUtil; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; /** * * @author Daniel Dietsch (dietsch@informatik.uni-freiburg.de) * */ public final class TestUtil { private static final long PSEUDO_RANDOM_FILE_SELECTION_SEED = 19120623; private TestUtil() { // utility classes should not be instantiated } /** * Select (n - offset) files from a collection of files in a pseudo-random and deterministic way. */ public static Collection limitFiles(final Collection files, final int offset, final int n) { if (files == null || n == 0) { return Collections.emptyList(); } else if (files.isEmpty() || n < 0) { return files; } else if (offset >= files.size()) { return Collections.emptyList(); } else if (offset == 0 && n >= files.size()) { return files; } else { final List shuffle = new ArrayList<>(files); Collections.shuffle(shuffle, new Random(PSEUDO_RANDOM_FILE_SELECTION_SEED)); int nPlusOffset; if ((long) offset + (long) n > Integer.MAX_VALUE) { nPlusOffset = Integer.MAX_VALUE; } else { nPlusOffset = offset + n; } final int upperIndex = Math.min(files.size(), nPlusOffset); return new ArrayList<>(shuffle.subList(offset, upperIndex)); } } /** * Generates a name based on the current time, the original name of the input file and the description string such * that it should be unique and recognizable. * * @param inputFile * An instance representing a file on the local machine * @param description * A description for the log file name. * @return A string representing the absolute path to a file on the local machine. */ public static String generateLogFilename(final File inputFile, final String description) { final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); final String dir = inputFile.getParent() + File.separator; final String originalFileName = inputFile.getName(); String name = "UltimateTest "; if (description != null && description.length() > 0) { name = name + description + "_"; } name = name + originalFileName + "_" + dateFormat.format(Calendar.getInstance().getTime()) + ".log"; name = name.replaceAll(" ", "_"); return dir + name; } /** * Combines a relative path with the base directory of this plugin, i.e. you can say * getPathFromHere("../../examples/settings/") to reach the setting directory * * @param path * A string representing a relative path. Please use "/" as path separator regardless of OS. Java will * recognize \\, but this wont work under Linux * @return A string representing the absolute path to the relative path based on the actual position of this package */ public static String getPathFromHere(final String path) { final File here = new File(System.getProperty("user.dir")); final File relative = new File(here.getAbsolutePath() + File.separator + path); return relative.getAbsolutePath(); } public static String getPathFromSurefire(final String path, final String canonicalClassName) { final File trunk = new File(System.getProperty("user.dir")); final File relative = new File(trunk.getAbsolutePath() + File.separator + "target" + File.separator + "surefire-reports" + File.separator + canonicalClassName + File.separator + path); return relative.getAbsolutePath(); } /** * Prefix the parameter "path" with the path to the trunk folder of the Ultimate repository on the current machine. * * Throws {@link IllegalArgumentException} if this path does not exist. */ public static String getPathFromTrunk(final String path) { final File trunk = new File(CoreUtil.WORKING_DIRECTORY).getParentFile().getParentFile(); final File relative = new File(trunk.getAbsolutePath() + File.separator + path); if (!relative.exists()) { throw new IllegalArgumentException("Path " + relative.getAbsolutePath() + " does not exist."); } return relative.getAbsolutePath(); } /** * Same as {@link #getPathFromTrunk(String)}, but creates non-existant paths instead of failing. */ public static String createPathFromTrunk(final String path) { final File trunk = new File(CoreUtil.WORKING_DIRECTORY).getParentFile().getParentFile(); final File relative = new File(trunk.getAbsolutePath() + File.separator + path); if (!relative.exists()) { relative.mkdirs(); } return relative.getAbsolutePath(); } public static String removeTrunkExamplesPrefix(final String path) { final String trunk = TestUtil.getPathFromTrunk(""); final String examples = trunk + File.separator + "examples" + File.separator; final int lastIndexOf = path.lastIndexOf(examples); if (lastIndexOf != -1) { final String trunkated = path.substring(lastIndexOf + examples.length(), path.length()); return trunkated; } return path; } public static String removeTrunkSettingsPrefix(final String path) { final String trunk = TestUtil.getPathFromTrunk(""); final String examples = trunk + File.separator + "examples" + File.separator + "settings" + File.separator; final int lastIndexOf = path.lastIndexOf(examples); if (lastIndexOf != -1) { final String trunkated = path.substring(lastIndexOf + examples.length(), path.length()); return trunkated; } return path; } public static String removeTrunkToolchainPrefix(final String path) { final String trunk = TestUtil.getPathFromTrunk(""); final String examples = trunk + File.separator + "examples" + File.separator + "toolchains" + File.separator; final int lastIndexOf = path.lastIndexOf(examples); if (lastIndexOf != -1) { final String trunkated = path.substring(lastIndexOf + examples.length(), path.length()); return trunkated; } return path; } /*** * Filters a list of files based on a given regex. Returns a collection of files of which the path matches the * regex. * * @param files * @param regex * @return */ public static Collection filterFiles(final Collection files, final String regex) { final ArrayList singleFiles = new ArrayList<>(); for (final File f : files) { final String path = f.getAbsolutePath(); if (path.matches(regex)) { singleFiles.add(f); } } return singleFiles; } /** * Get absolute path for the file in which an ITestLogfile will be written. This includes also the filename. */ public static String generateAbsolutePathForLogfile(final ITestLogfile testSummary) { final String absolutPath = TestUtil.getPathFromSurefire(generateLogFilename(testSummary), testSummary.getUltimateTestSuiteClass().getCanonicalName()); return absolutPath; } /** * Get filename for the file in which an ITestSummary will be written. Returns only the name of the file without * directories. */ public static String generateLogFilename(final ITestLogfile testSummary) { final String filename = testSummary.getDescriptiveLogName() + "_" + de.uni_freiburg.informatik.ultimate.util.CoreUtil.getCurrentDateTimeAsString() + testSummary.getFilenameExtension(); return filename; } public static String generateLogFilename(final String directory, String description) { if (description == null) { description = ""; } if (description.length() > 0) { description = description + " "; } final File f = new File(directory); String dir = ""; if (f.isDirectory()) { dir = f + File.separator; } else { dir = f.getParent() + File.separator; } final String name = "UltimateTest Summary " + description + de.uni_freiburg.informatik.ultimate.util.CoreUtil.getCurrentDateTimeAsString() + ".log"; return dir + name; } public static String getRegexFromFileendings(final String[] fileendings) { if (fileendings == null || fileendings.length == 0) { return ".*"; } final StringBuilder sb = new StringBuilder(); sb.append("("); sb.append("\\").append(fileendings[0]); for (int i = 1; i < fileendings.length; i++) { sb.append("|\\").append(fileendings[i]); } sb.append(")$"); return sb.toString(); } public static List getFiles(final File root, final String... endings) { final List rtr = new ArrayList<>(); if (root.isFile()) { for (final String s : endings) { if (root.getAbsolutePath().endsWith(s)) { rtr.add(root); break; } } return rtr; } final File[] list = root.listFiles(); if (list == null) { return rtr; } for (final File f : list) { rtr.addAll(getFiles(f, endings)); } return rtr; } public static Predicate getFileEndingTest(final String... endings) { return file -> { if (!file.isFile()) { return false; } final String abspath = file.getAbsolutePath(); for (final String s : endings) { if (abspath.endsWith(s)) { return true; } } return false; }; } public static Predicate getRegexTest(final String... regexes) { if (regexes == null || regexes.length == 0) { return file -> file != null; } return file -> file != null && matchRegexStream(file, Arrays.stream(regexes)); } public static Predicate getRegexTest(final Collection regexes) { if (regexes.isEmpty()) { return file -> file != null; } return file -> file != null && matchRegexStream(file, regexes.stream()); } private static boolean matchRegexStream(final File file, final Stream regexStream) { return regexStream.filter(a -> a != null && !a.isEmpty()) .allMatch(regex -> file.getAbsolutePath().matches(regex)); } /** * Returns recursively all files in a directory that have a path whose suffix beyond root is matched by regex. If * root is a file, a collection containing root is returned (ignoring the regex) E.g., your file root has the * absolute path /home/horst/ultimate/ and your regex is *horst* you obtain the files that contain the String * "horst" if the prefix "/home/horst/ultimate/" was removed. * * @param root * @param regex * @return */ public static Collection getFilesRegex(final File root, final String[] regex) { return getFilesRegex(root.getAbsolutePath(), root, regex); } /** * Returns recursively all files in a directory that have a path whose suffix beyond the String prefix is matched by * regex. If root is a file, a collection containing root is returned (ignoring the regex). * * @param root * @param regex * @return */ private static Collection getFilesRegex(final String prefix, final File root, final String[] regex) { if (!root.getAbsolutePath().startsWith(prefix)) { throw new IllegalArgumentException("prefix is no prefix of root.getAbsolutePath()"); } final List rtr = new ArrayList<>(); if (root.isFile()) { rtr.add(root); return rtr; } final File[] list = root.listFiles(); if (list == null) { return rtr; } for (final File f : list) { if (f.isDirectory()) { rtr.addAll(getFilesRegex(prefix, f, regex)); } else if (regex == null || regex.length == 0) { rtr.add(f); } else { for (final String s : regex) { final String suffix = f.getAbsolutePath().substring(prefix.length()); if (suffix.matches(s)) { rtr.add(f); break; } } } } return rtr; } public static Collection uniformN(final Collection collection, final int n) { final List rtr = new ArrayList<>(n); final int size = collection.size(); int step = 1; if (n != 0) { step = (int) Math.floor((double) size / (double) n); } int i = 1; for (final E elem : collection) { if (i % step == 0) { rtr.add(elem); } ++i; } return rtr; } public static void logResults(final Class caller, final String inputFile, final boolean fail, final Collection customMessages, final IUltimateServiceProvider services) { final ILogger logger = services.getLoggingService().getLogger(caller); logResults(logger, inputFile, fail, customMessages, services.getResultService()); } public static void logResults(final ILogger logger, final String inputFile, final boolean fail, final Collection customMessages, final IResultService resultService) { if (logger == null) { logResults(message -> System.err.println(message), inputFile, fail, customMessages, resultService); } else { logResults(message -> logger.info(message), inputFile, fail, customMessages, resultService); } } private static void logResults(final ILogWriter logger, final String inputFile, final boolean fail, final Collection customMessages, final IResultService resultService) { logger.write("#################### TEST RESULT ####################"); logger.write("Results for " + inputFile); if (resultService == null) { logger.write("There is no IResultService (this indicates that Ultimate terminated abnormally"); } else { for (final Entry> entry : resultService.getResults().entrySet()) { int i = 0; for (final IResult result : entry.getValue()) { logger.write(String.format("[%s] %s --> [%s] %s", i, entry.getKey(), result.getClass().getSimpleName(), result.getLongDescription())); ++i; } } } if (customMessages != null && !customMessages.isEmpty()) { for (final String s : customMessages) { if (s != null) { logger.write(s); } } } if (fail) { logger.write("TEST FAILED"); } else { logger.write("TEST SUCCEEDED"); } // Get current size of heap in bytes final long heapSize = Runtime.getRuntime().totalMemory(); // Get amount of free memory within the heap in bytes. This size will // increase // after garbage collection and decrease as new objects are // created. final long heapFreeSize = Runtime.getRuntime().freeMemory(); // Get maximum size of heap in bytes. The heap cannot grow beyond this // size.// Any attempt will result in an OutOfMemoryException. final long heapMaxSize = Runtime.getRuntime().maxMemory(); logger.write(String.format("Statistics: heapSize=%s heapFreeSize=%s heapMaxSize=%s", CoreUtil.humanReadableByteCount(heapSize, true), CoreUtil.humanReadableByteCount(heapFreeSize, true), CoreUtil.humanReadableByteCount(heapMaxSize, true))); logger.write("#################### END TEST RESULT ####################"); } /** * Returns a map from keywords to verification results. We use keywords in filenames to specify expected * verification results. If a key of this map is a substring of the filename, the value of this map is the expected * verification result of a safety checker. */ public static Map constructFilenameKeywordMap_AllSafetyChecker() { final Map map = new HashMap<>(); map.put(".*-safe.*", SafetyCheckerOverallResult.SAFE); map.put(".*_safe.*", SafetyCheckerOverallResult.SAFE); map.put(".*-Safe.*", SafetyCheckerOverallResult.SAFE); map.put(".*_Safe.*", SafetyCheckerOverallResult.SAFE); map.put(".*-unsafe.*", SafetyCheckerOverallResult.UNSAFE); map.put(".*_unsafe.*?!(.*_false-valid-deref.*)", SafetyCheckerOverallResult.UNSAFE); map.put(".*-Unsafe.*", SafetyCheckerOverallResult.UNSAFE); map.put(".*_Unsafe.*", SafetyCheckerOverallResult.UNSAFE); map.putAll(constructFilenameKeywordMap_SvcompReach()); map.putAll(constructFilenameKeywordMap_SvcompMemsafety()); map.putAll(constructFilenameKeywordMap_SvcompOverflow()); return map; } public static final String SVCOMP_PROP_NOOVERFLOW = "no-overflow.prp"; public static final String SVCOMP_PROP_TERMINATION = "termination.prp"; public static final String SVCOMP_PROP_UNREACHCALL = "unreach-call.prp"; public static final String SVCOMP_PROP_VALIDMEMCLEANUP = "valid-memcleanup.prp"; public static final String SVCOMP_PROP_VALIDMEMSAFETY = "valid-memsafety.prp"; public static final String SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDFREE = "valid-free"; public static final String SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDDEREF = "valid-deref"; public static final String SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDMEMTRACK = "valid-memtrack"; public static NestedMap2 constructPropertyMapSvcompSafety(final String... propertyFiles) { final NestedMap2 map = new NestedMap2<>(); for (final String propertyFile : propertyFiles) { switch (propertyFile) { case SVCOMP_PROP_NOOVERFLOW: case SVCOMP_PROP_UNREACHCALL: map.put(propertyFile, String.valueOf(true), SafetyCheckerOverallResult.SAFE); map.put(propertyFile, String.valueOf(false), SafetyCheckerOverallResult.UNSAFE); break; case SVCOMP_PROP_VALIDMEMCLEANUP: map.put(propertyFile, String.valueOf(true), SafetyCheckerOverallResult.SAFE); map.put(propertyFile, String.valueOf(false), SafetyCheckerOverallResult.UNSAFE_MEMTRACK); break; case SVCOMP_PROP_VALIDMEMSAFETY: map.put(propertyFile, String.valueOf(true), SafetyCheckerOverallResult.SAFE); map.put(propertyFile, SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDFREE, SafetyCheckerOverallResult.UNSAFE_FREE); map.put(propertyFile, SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDDEREF, SafetyCheckerOverallResult.UNSAFE_DEREF); map.put(propertyFile, SVCOMP_VALIDMEMSAFETY_SUBPROP_VALIDMEMTRACK, SafetyCheckerOverallResult.UNSAFE_MEMTRACK); break; default: throw new AssertionError("unknown property file " + propertyFile); } } return map; } public static NestedMap2 constructPropertyMapSvcompTermination(final String... propertyFiles) { final NestedMap2 map = new NestedMap2<>(); for (final String propertyFile : propertyFiles) { switch (propertyFile) { case SVCOMP_PROP_TERMINATION: map.put(propertyFile, String.valueOf(true), TerminationAnalysisOverallResult.TERMINATING); map.put(propertyFile, String.valueOf(false), TerminationAnalysisOverallResult.NONTERMINATING); break; default: throw new AssertionError("unknown property file " + propertyFile); } } return map; } /** * Returns a map from SV-COMP filename keywords to verification results for the error function reachability * specification. */ public static Map constructFilenameKeywordMap_SvcompReach() { final Map map = new HashMap<>(); // true-unreach-call is the SV-COMP annotation for safe wrt. reachability of error function map.put(".*_true-unreach-call.*", SafetyCheckerOverallResult.SAFE); // false-unreach-call is the SV-COMP annotation for unsafe wrt. reachability of error function map.put(".*_false-unreach-call.*", SafetyCheckerOverallResult.UNSAFE); return map; } /** * Returns a map from SV-COMP filename keywords to verification results for memsafety specification. */ public static Map constructFilenameKeywordMap_SvcompMemsafety() { final Map map = new HashMap<>(); map.put(".*_true-valid-memsafety.*", SafetyCheckerOverallResult.SAFE); // false-valid-deref is the SV-COMP annotation for unsafe wrt. pointer // dereference map.put(".*_false-valid-deref.*", SafetyCheckerOverallResult.UNSAFE_DEREF); // false-valid-free is the SV-COMP annotation for unsafe wrt. free map.put(".*_false-valid-free.*", SafetyCheckerOverallResult.UNSAFE_FREE); // false-valid-memtrack is the SV-COMP annotation for unsafe wrt. memory // leaks map.put(".*_false-valid-memtrack.*", SafetyCheckerOverallResult.UNSAFE_MEMTRACK); return map; } /** * Returns a map from SV-COMP filename keywords to verification results for overflow specification. */ public static Map constructFilenameKeywordMap_SvcompOverflow() { final Map map = new HashMap<>(); // no-overflow is SV-COMP annotation for signed integer overflows map.put(".*_true-no-overflow.*", SafetyCheckerOverallResult.SAFE); map.put(".*_false-no-overflow.*", SafetyCheckerOverallResult.UNSAFE); return map; } /** * Returns a map from keywords to verification results. We use keywords in the first line of files to specify * expected verification results. If a key of this map is a substring of the first line, the value of this map is * the expected verification result of a safety checker. */ public static Map constructFirstlineKeywordMap_SafetyChecker() { final Map map = new HashMap<>(); map.put("#Safe", SafetyCheckerOverallResult.SAFE); map.put("#Unsafe", SafetyCheckerOverallResult.UNSAFE); map.put("#Unknown", SafetyCheckerOverallResult.UNKNOWN); map.put("#ValidAnnotation", SafetyCheckerOverallResult.VALID_ANNOTATION); map.put("#InvalidAnnotation", SafetyCheckerOverallResult.INVALID_ANNOTATION); map.put("#SyntaxError", SafetyCheckerOverallResult.SYNTAX_ERROR); return map; } /** * Returns a map from keywords to verification results. We use keywords in filenames to specify expected * verification results. If a key of this map is a substring of the filename, the value of this map is the expected * verification result of a termination analysis. */ public static Map constructFilenameKeywordMap_TerminationAnalysis() { final Map map = new HashMap<>(); // true-unreach-call is the SV-COMP annotation for safe map.put(".*_true-termination.*", TerminationAnalysisOverallResult.TERMINATING); // false-unreach-call is the SV-COMP annotation for safe map.put(".*_false-termination.*", TerminationAnalysisOverallResult.NONTERMINATING); return map; } /** * Returns a map from keywords to verification results. We use keywords in paths to specify expected verification * results. If a key of this map is a substring of the path, the value of this map is the expected verification * result of a termination analysis. */ public static Map constructPathKeywordMap_TerminationAnalysis() { final Map map = new HashMap<>(); // we sometimes put terminating examples in a folder with this name map.put("/terminating", TerminationAnalysisOverallResult.TERMINATING); // we sometimes put nonterminating examples in a folder with this name map.put("/nonterminating", TerminationAnalysisOverallResult.NONTERMINATING); return map; } /** * Returns a map from keywords to verification results. We use keywords in the first line of files to specify * expected verification results. If a key of this map is a substring of the first line, the value of this map is * the expected verification result of a termination analysis. */ public static Map constructFirstlineKeywordMap_TerminationAnalysis() { final Map map = new HashMap<>(); map.put("#rTerminationDerivable", TerminationAnalysisOverallResult.TERMINATING); map.put("#rTermination", TerminationAnalysisOverallResult.TERMINATING); map.put("#Terminating", TerminationAnalysisOverallResult.TERMINATING); map.put("#rNonTerminationDerivable", TerminationAnalysisOverallResult.NONTERMINATING); map.put("#rNonTermination", TerminationAnalysisOverallResult.NONTERMINATING); map.put("#Nonterminating", TerminationAnalysisOverallResult.NONTERMINATING); map.put("#SyntaxError", TerminationAnalysisOverallResult.SYNTAX_ERROR); return map; } /** * Returns a map from keywords to verification results. We use keywords in the first line of files to specify * expected verification results. If a key of this map is a substring of the first line, the value of this map is * the expected verification result of a termination analysis. */ public static Map constructFirstlineKeywordMap_Termcomp2016() { final Map map = new HashMap<>(); map.put("#termcomp16-someonesaidyes", TerminationAnalysisOverallResult.TERMINATING); map.put("#termcomp16-someonesaidno", TerminationAnalysisOverallResult.NONTERMINATING); return map; } /** * Returns the first line of File file as String. */ public static String extractFirstLine(final File file) { BufferedReader br; String line = null; try { br = new BufferedReader(new FileReader(file)); line = br.readLine(); br.close(); } catch (final IOException e) { throw new AssertionError("unable to read file " + file); } return line; } /** * Returns the line of File file that starts with "(set-info :status", or null if there is no such line */ public static String extractSMTLibStatusInfo(final File file) { try (BufferedReader br = new BufferedReader(new FileReader(file))) { while (true) { final String line = br.readLine(); if (line == null) { return null; } if (line.trim().startsWith("(set-info :status")) { // found the status return line; } if (line.trim().startsWith("(assert")) { // found an assert before the status information --> file does not seem to contain status info return null; } } } catch (final IOException e) { throw new AssertionError("unable to read file " + file); } } /** * Returns an absolute path to the SVCOMP root directory specified by the Maven variable "svcompdir". If there is no * variable with such a name, the parameter fallback will be used. The method converts relative paths to absolute * ones. * * @param fallback * A string describing a relative or absolute path to an existing directory (which is hopefully the * SVCOMP root directory). * @return An absolute path to an existing directory or null */ public static String getFromMavenVariableSVCOMPRoot(final String fallback) { String svcompDir = makeAbsolutePath(System.getProperty("svcompdir")); if (svcompDir != null) { return svcompDir; } svcompDir = makeAbsolutePath(fallback); return svcompDir; } /** * Converts a relative path to an absolute one and checks if this path exists. * * @param somepath * A relative or absolute path * @return An absolute path to an existing file or directory or null */ public static String makeAbsolutePath(final String somepath) { if (somepath == null) { return null; } File path = new File(somepath); if (!path.isAbsolute()) { path = new File(TestUtil.getPathFromTrunk(path.getPath())); } if (path.exists()) { return path.getAbsolutePath(); } return null; } public static void writeNonIncrementalLog(final INonIncrementalLog nonIncrementalLog, final ILogger logger) { final File logFile = new File(TestUtil.generateAbsolutePathForLogfile(nonIncrementalLog)); if (!logFile.isDirectory()) { if (!logFile.getParentFile().mkdirs()) { if (!logFile.getParentFile().isDirectory()) { logger.warn("Did not create parent directory: " + logFile.getParentFile()); } } } final String summaryLog = nonIncrementalLog.getLog().trim(); if (summaryLog == null || summaryLog.isEmpty()) { logger.warn(nonIncrementalLog.getClass() + " is empty"); return; } try { final FileWriter writer = new FileWriter(logFile); logger.info("Writing " + nonIncrementalLog.getDescriptiveLogName() + " for " + nonIncrementalLog.getUltimateTestSuiteClass().getCanonicalName() + " to " + logFile.getAbsolutePath()); writer.write(summaryLog); writer.close(); } catch (final IOException e) { logger.fatal("Exception while writing to " + logFile.getAbsolutePath(), e); } } /** * The JUnit view in Eclipse limits the length of the test case name to a certain length. You cannot rerun tests in * the GUI if two test cases have the same prefix, and you cannot rerun tests if their name exceeds this length. * This methods tries to reduce the length of the string representing a test case name such that this limit is not * reached. * * @param testCaseName * The original test case name. * @param class1 * @return The minimized test case name. */ public static String minimizeTestCaseName(final String testCaseName, final int testsuiteFQDNlength) { if (null == testCaseName) { return null; } /* * It seems like Eclipse wants to write to * "/source/.metadata/.plugins/org.eclipse.debug.core/.launches/Rerun * ..launch", and Windows limits path segments to 255 chars. * * For Linux, Eclipse's limit of 255 chars is the hard cap. */ final int maxLength; if (CoreUtil.OS_IS_WINDOWS) { maxLength = 255 - testsuiteFQDNlength - "Rerun ..launch".length(); } else { maxLength = 255; } final String replacement = "_"; String rtr = testCaseName; rtr = rtr.replaceAll("Input:", "I:"); rtr = rtr.replaceAll("Settings:", "S:"); rtr = rtr.replaceAll("Toolchain:", "T:"); rtr = rtr.replaceAll(":", replacement); rtr = rtr.replaceAll("/", replacement); if (rtr.length() > maxLength) { final String currentSuffix = String.valueOf(rtr.hashCode()); rtr = rtr.substring(0, maxLength - 1 - currentSuffix.length()); rtr = rtr + replacement + currentSuffix; } return rtr; } private interface ILogWriter { public void write(String message); } }