From 354ece209ec70020eddf99fa5736f3914b73640d Mon Sep 17 00:00:00 2001 From: Vodorok Date: Tue, 23 Jul 2019 16:20:33 +0200 Subject: [PATCH 1/4] Add new CodeChecker resolution logic Refactored the logic, how CodeChecker is found and configured. There is now an internal representation of a CodeChecker. There are a locator service introduced to handle CodeChecker resolution. There are a new gui radio button group to select how CodeChecker should be found. There is a proper dynamic widget enablement function depending on the selected options, and more verbose messages for the preferences panel. --- .../plugin/codechecker/CodeChecker.java | 75 ++++ .../codechecker/CodeCheckerFactory.java | 17 + .../plugin/codechecker/ICodeChecker.java | 55 +++ .../codechecker/ICodeCheckerFactory.java | 25 ++ .../locator/CodeCheckerLocatorFactory.java | 27 ++ .../locator/CodeCheckerLocatorService.java | 30 ++ .../CustomBuiltCodeCheckerLocatorService.java | 53 +++ .../locator/EnvCodeCheckerLocatorService.java | 30 ++ .../locator/InvalidCodeCheckerException.java | 17 + .../PreBuiltCodeCheckerLocatorService.java | 29 ++ .../locator/ResolutionMethodTypes.java | 41 ++ .../codechecker/locator/package-info.java | 4 + .../plugin/codechecker/package-info.java | 4 + .../plugin/config/CcConfigurationBase.java | 19 + .../eclipse/plugin/config/CommonGui.java | 377 +++++++++++++----- .../eclipse/plugin/config/Config.java | 4 +- .../config/project/CodeCheckerProject.java | 11 +- .../eclipse/plugin/report/job/AnalyzeJob.java | 93 +++-- .../runtime/CodeCheckEnvironmentChecker.java | 190 --------- .../plugin/runtime/CodeCheckerLocator.java | 40 -- .../plugin/runtime/EnvironmentParser.java | 22 - .../runtime/IShellExecutorHelperFactory.java | 17 + .../runtime/ShellExecutorHelperFactory.java | 15 + .../eclipse/plugin/runtime/package-info.java | 4 + .../runtime/CodeCheckerLocatorTest.java | 105 ----- .../plugin/runtime/EnvironmentParserTest.java | 32 -- 26 files changed, 796 insertions(+), 540 deletions(-) create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerFactory.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeChecker.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeCheckerFactory.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorFactory.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorService.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/EnvCodeCheckerLocatorService.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/InvalidCodeCheckerException.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/PreBuiltCodeCheckerLocatorService.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/ResolutionMethodTypes.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/package-info.java delete mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckEnvironmentChecker.java delete mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocator.java delete mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParser.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/IShellExecutorHelperFactory.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/ShellExecutorHelperFactory.java create mode 100644 bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/package-info.java delete mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocatorTest.java delete mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParserTest.java diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java new file mode 100644 index 00000000..d95ad2d1 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeChecker.java @@ -0,0 +1,75 @@ +package org.codechecker.eclipse.plugin.codechecker; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.config.CcConfigurationBase; +import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; +import org.codechecker.eclipse.plugin.runtime.LogI; +import org.codechecker.eclipse.plugin.runtime.SLogger; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; +import org.eclipse.core.runtime.IProgressMonitor; + +import com.google.common.base.Optional; + +/** + * Internal representation of a CodeChecker package. + */ +public class CodeChecker implements ICodeChecker { + + private Path location; + private ShellExecutorHelper she; + + /** + * + * @param path + * Path to the binary itself. + * @param she + * The ShellExecutor to be used. + * + * @throws InvalidCodeCheckerException + * Thrown when no CodeChecker found. + */ + public CodeChecker(Path path, ShellExecutorHelper she) throws InvalidCodeCheckerException { + location = path; + this.she = she; + getVersion(); + } + + @Override + public String getCheckers() { + String cmd = location.toAbsolutePath().toString() + " checkers"; + Optional ccOutput = she.waitReturnOutput(cmd, false); + return ccOutput.or("No Checkers found"); + } + + @Override + public String getVersion() throws InvalidCodeCheckerException { + String cmd = location.toAbsolutePath().toString() + " version"; + Optional ccOutput = she.waitReturnOutput(cmd, false); + if (!ccOutput.isPresent() || ccOutput.get().isEmpty()) + throw new InvalidCodeCheckerException("Couldn't run CodeChecker version!"); + return ccOutput.get(); + } + + @Override + public Path getLocation() { + return location; + } + + @Override + public String analyze(Path logFile, boolean logToConsole, IProgressMonitor monitor, int taskCount, + CcConfigurationBase config) { + + String cmd = location.toAbsolutePath().toString() + " analyze " + config.get(ConfigTypes.CHECKER_LIST) + " -j " + + config.get(ConfigTypes.ANAL_THREADS) + " -n javarunner" + " -o " + + logFile.toAbsolutePath().getParent().toString() + "/results/ " + + logFile.toAbsolutePath().toString(); + + SLogger.log(LogI.INFO, "Running analyze Command: " + cmd); + Optional ccOutput = she.progressableWaitReturnOutput(cmd, logToConsole, monitor, taskCount); + + return ccOutput.or(""); + } + +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerFactory.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerFactory.java new file mode 100644 index 00000000..613f095c --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerFactory.java @@ -0,0 +1,17 @@ +package org.codechecker.eclipse.plugin.codechecker; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; + +/** + * Implementation of the {@link ICodeCheckerFactory} interface. + */ +public class CodeCheckerFactory implements ICodeCheckerFactory { + @Override + public ICodeChecker createCodeChecker(Path pathToBin, ShellExecutorHelper she) + throws InvalidCodeCheckerException { + return new CodeChecker(pathToBin, she); + } +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeChecker.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeChecker.java new file mode 100644 index 00000000..f8075d4b --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeChecker.java @@ -0,0 +1,55 @@ +package org.codechecker.eclipse.plugin.codechecker; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.config.CcConfigurationBase; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Interface representing a CodeChecker package. + */ +public interface ICodeChecker { + /** + * Returns the unformatted output of the CodeChecker checkers command. + * + * @return The checker list. + */ + public String getCheckers(); + + /** + * Returns the full and complete version string of the CodeChecker package. + * + * @return The version String. + * @throws InvalidCodeCheckerException + * Thrown when no version string can be returned. + */ + public String getVersion() throws InvalidCodeCheckerException; + + /** + * To get the location of the CodeChecker binary. + * + * @return The path. + */ + public Path getLocation(); + + /** + * Executes CodeChecker check command on the build log received in the fileName + * parameter. + * + * @param logFile + * A Path to the build log in the followin format: + * http://clang.llvm.org/docs/JSONCompilationDatabase.html . + * @param logToConsole + * Flag for indicating console logging. + * @param monitor + * ProgressMonitor for to be able to increment progress bar. + * @param taskCount + * How many analyze step to be taken. + * @param config + * The configuration being used. + * @return CodeChecker The full analyze command output. + */ + public String analyze(Path logFile, boolean logToConsole, IProgressMonitor monitor, int taskCount, + CcConfigurationBase config); +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeCheckerFactory.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeCheckerFactory.java new file mode 100644 index 00000000..af7a9718 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/ICodeCheckerFactory.java @@ -0,0 +1,25 @@ +package org.codechecker.eclipse.plugin.codechecker; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; + +/** + * Interface for CodeChecker factory. + */ +public interface ICodeCheckerFactory { + /** + * Method for creating CodeChecker instances. + * + * @param pathToBin + * Path to the CodeChecker binary. (Not to root!) + * @param she + * The shell executor helper that will be used. + * @return A newly created {@link ICodeChecker} ICodeChecker instance. + * @throws InvalidCodeCheckerException + * Thrown when a new instance couldn't be created. + */ + public ICodeChecker createCodeChecker(Path pathToBin, ShellExecutorHelper she) + throws InvalidCodeCheckerException; +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorFactory.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorFactory.java new file mode 100644 index 00000000..f2e7a75f --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorFactory.java @@ -0,0 +1,27 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +/** + * Class responsible to create {@link CodeCheckerLocatorService} instances. + */ +public class CodeCheckerLocatorFactory { + /** + * Returns a {@link CodeCheckerLocatorService} depending on a the input + * parameter. + * + * @param t + * Any of the {@link ResolutionMethodTypes} enum values. + * @return A {@link CodeCheckerLocatorService} instance. + */ + public CodeCheckerLocatorService create(ResolutionMethodTypes t) { + switch (t) { + case PATH: + return new EnvCodeCheckerLocatorService(); + case PRE: + return new PreBuiltCodeCheckerLocatorService(); + case PY: + return new CustomBuiltCodeCheckerLocatorService(); + default: + return null; + } + } +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorService.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorService.java new file mode 100644 index 00000000..f81b75d7 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorService.java @@ -0,0 +1,30 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; +import org.codechecker.eclipse.plugin.codechecker.ICodeCheckerFactory; +import org.codechecker.eclipse.plugin.runtime.IShellExecutorHelperFactory; + +/** + * Implementations of this interface should return the location of the + * CodeChecker package. + */ +public abstract class CodeCheckerLocatorService { + /** + * @param pathToBin + * Path to CodeChecker package root. + * @param pathToVenv + * Path to the root of the virtual environment. + * @param ccfactory + * An {@link ICodeCheckerFactory} that will create the CodeChecker. + * @param sheFactory + * A {@link IShellExecutorHelperFactory} to be used. + * @return A CodeChecker Instance. + * @throws InvalidCodeCheckerException + * Thrown when the {@link ICodeChecker} instantiation fails. + */ + public abstract ICodeChecker findCodeChecker(Path pathToBin, Path pathToVenv, ICodeCheckerFactory ccfactory, + IShellExecutorHelperFactory sheFactory) + throws InvalidCodeCheckerException; +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java new file mode 100644 index 00000000..655eada6 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java @@ -0,0 +1,53 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +import java.nio.file.Path; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; +import org.codechecker.eclipse.plugin.codechecker.ICodeCheckerFactory; +import org.codechecker.eclipse.plugin.runtime.IShellExecutorHelperFactory; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; + +import com.google.common.base.Optional; + +/** + * Provides a CodeChecker instance which is tied to a Custom built CodeChecker + * package. + */ +public class CustomBuiltCodeCheckerLocatorService extends CodeCheckerLocatorService { + public static final String ERROR = "Couldn't find CodeChecker at the given destination!"; + public static final String ENV_ERROR = "There was an error when reading the given python environment!"; + + @Override + public ICodeChecker findCodeChecker(Path pathToBin, Path pathToVenv, + ICodeCheckerFactory ccfactory, IShellExecutorHelperFactory sheFactory) throws InvalidCodeCheckerException { + + ShellExecutorHelper she = sheFactory.createShellExecutorHelper(System.getenv()); + Optional output = she + .quickReturnOutput("source " + pathToVenv.toAbsolutePath().toString() + "/bin/activate ; env"); + if (!output.isPresent()) + throw new IllegalArgumentException(); + try { + Map env = parseEnvironment(output.get()); + ShellExecutorHelper pyShe = sheFactory.createShellExecutorHelper(env); + return ccfactory.createCodeChecker(pathToBin, pyShe); + } catch (ArrayIndexOutOfBoundsException e) { + throw new ArrayIndexOutOfBoundsException(ENV_ERROR); + } catch (InvalidCodeCheckerException e) { + throw new InvalidCodeCheckerException(ERROR); + } + } + + /** + * Returns a String - String map from a raw "Key=Value\n..." String. + * @param envOutput The String input. + * @return A Map containing all the environment variables. + */ + private Map parseEnvironment(String envOutput){ + Map map = Stream.of(envOutput.split("\n")).map(String::trim).map(line -> line.split("=")) + .collect(Collectors.toMap(k -> k[0], v -> v.length < 2 ? "" : v[1])); + return map; + } +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/EnvCodeCheckerLocatorService.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/EnvCodeCheckerLocatorService.java new file mode 100644 index 00000000..3f317933 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/EnvCodeCheckerLocatorService.java @@ -0,0 +1,30 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; +import org.codechecker.eclipse.plugin.codechecker.ICodeCheckerFactory; +import org.codechecker.eclipse.plugin.runtime.IShellExecutorHelperFactory; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; + +/** + * Provides a CodeChecker instance tied to a CodeChecker package resulting of + * "which CodeChecker". + */ +public class EnvCodeCheckerLocatorService extends CodeCheckerLocatorService { + public static final String ERROR = "CodeChecker wasn't found in PATH environment variable!"; + + @Override + public ICodeChecker findCodeChecker(Path path, Path pathToVenv, + ICodeCheckerFactory ccFactory, IShellExecutorHelperFactory sheFactory) throws InvalidCodeCheckerException { + + ShellExecutorHelper she = sheFactory.createShellExecutorHelper(System.getenv()); + String location = she.quickReturnFirstLine("which CodeChecker").or(""); + try { + return ccFactory.createCodeChecker(Paths.get(location), she); + } catch (InvalidCodeCheckerException e) { + throw new InvalidCodeCheckerException(ERROR); + } + } +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/InvalidCodeCheckerException.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/InvalidCodeCheckerException.java new file mode 100644 index 00000000..93134481 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/InvalidCodeCheckerException.java @@ -0,0 +1,17 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +/** + * Custom exception indicating a failed CodeChecker instance creation. + */ +@SuppressWarnings("serial") +public class InvalidCodeCheckerException extends Exception { + /** + * Ctor. + * + * @param errorMessage + * Error message. + */ + public InvalidCodeCheckerException(String errorMessage) { + super(errorMessage); + } +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/PreBuiltCodeCheckerLocatorService.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/PreBuiltCodeCheckerLocatorService.java new file mode 100644 index 00000000..4ff90c00 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/PreBuiltCodeCheckerLocatorService.java @@ -0,0 +1,29 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +import java.nio.file.Path; + +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; +import org.codechecker.eclipse.plugin.codechecker.ICodeCheckerFactory; +import org.codechecker.eclipse.plugin.runtime.IShellExecutorHelperFactory; + +/** + * Provides a CodeChecker instance which is tied to a pre-built CodeChecker + * package. + */ +public class PreBuiltCodeCheckerLocatorService extends CodeCheckerLocatorService { + public static final String INVALID = "The path to the CodeChecker binary is not valid"; + public static final String ERROR = "Couldn't find CodeChecker at the given destination!"; + + @Override + public ICodeChecker findCodeChecker(Path pathToBin, Path pathToVenv, + ICodeCheckerFactory ccfactory, IShellExecutorHelperFactory sheFactory) throws InvalidCodeCheckerException { + if (pathToBin == null) + throw new IllegalArgumentException(INVALID); + try { + return ccfactory.createCodeChecker(pathToBin, sheFactory.createShellExecutorHelper(System.getenv())); + } catch (InvalidCodeCheckerException e) { + throw new InvalidCodeCheckerException(ERROR); + } + } + +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/ResolutionMethodTypes.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/ResolutionMethodTypes.java new file mode 100644 index 00000000..f989c2b3 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/ResolutionMethodTypes.java @@ -0,0 +1,41 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +/** + * This enum represents the available types of CodeChecker resolution methods. + */ +public enum ResolutionMethodTypes { + PATH("PATH"), PRE("PRE"), PY("PY"); + + private String value; + + /** + * + * @param def utility method for setting the default value. + */ + private ResolutionMethodTypes(String def) { + this.value = def; + } + + /** + * + * @return Returns the value associated with the enum. + */ + public String getDefaultValue() { + return value; + } + + /** + * + * @param s + * The query string. + * @return The matching ResolutionMethodTypes if exists null otherwise. + */ + public static ResolutionMethodTypes getFromString(String s) { + for (ResolutionMethodTypes r : ResolutionMethodTypes.values()) { + if (s.equals(r.toString())) + return r; + } + return null; + } + +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java new file mode 100644 index 00000000..3c866f38 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java @@ -0,0 +1,4 @@ +/** + * CodeChecker locator related classes. + */ +package org.codechecker.eclipse.plugin.codechecker.locator; \ No newline at end of file diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/package-info.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/package-info.java new file mode 100644 index 00000000..39fe37d6 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/package-info.java @@ -0,0 +1,4 @@ +/** + * CodeChecker related classes. + */ +package org.codechecker.eclipse.plugin.codechecker; \ No newline at end of file diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CcConfigurationBase.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CcConfigurationBase.java index 7d056af0..1df9db66 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CcConfigurationBase.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CcConfigurationBase.java @@ -5,6 +5,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; import org.eclipse.core.runtime.preferences.IEclipsePreferences; @@ -17,6 +18,7 @@ public abstract class CcConfigurationBase { protected Map config; protected IEclipsePreferences preferences; + protected ICodeChecker codeChecker; private final Set listeners = new HashSet<>(); @@ -49,6 +51,23 @@ public CcConfigurationBase(CcConfigurationBase other) { */ protected abstract void validate(); + /** + * @return The CodeChecker being used. + */ + public ICodeChecker getCodeChecker() { + return codeChecker; + } + + /** + * Sets the currently used CodeChecker. + * + * @param codeChecker + * The CodeChecker that will be stored. + */ + public void setCodeChecker(ICodeChecker codeChecker) { + this.codeChecker = codeChecker; + } + /** * @return the internal configuration. */ diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CommonGui.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CommonGui.java index da751a3c..3038cd20 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CommonGui.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/CommonGui.java @@ -1,15 +1,36 @@ package org.codechecker.eclipse.plugin.config; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.codechecker.eclipse.plugin.Logger; +import org.codechecker.eclipse.plugin.codechecker.CodeCheckerFactory; +import org.codechecker.eclipse.plugin.codechecker.ICodeChecker; +import org.codechecker.eclipse.plugin.codechecker.locator.CodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.CustomBuiltCodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.EnvCodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.codechecker.locator.PreBuiltCodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.ResolutionMethodTypes; +import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; +import org.codechecker.eclipse.plugin.config.global.CcGlobalConfiguration; +import org.codechecker.eclipse.plugin.config.project.CodeCheckerProject; +import org.codechecker.eclipse.plugin.itemselector.CheckerView; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelperFactory; +import org.codechecker.eclipse.plugin.utils.CheckerItem; +import org.codechecker.eclipse.plugin.utils.CheckerItem.LAST_ACTION; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; @@ -18,9 +39,9 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; @@ -30,14 +51,6 @@ import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; -import org.codechecker.eclipse.plugin.Logger; -import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; -import org.codechecker.eclipse.plugin.config.global.CcGlobalConfiguration; -import org.codechecker.eclipse.plugin.config.project.CodeCheckerProject; -import org.codechecker.eclipse.plugin.itemselector.CheckerView; -import org.codechecker.eclipse.plugin.runtime.CodeCheckEnvironmentChecker; -import org.codechecker.eclipse.plugin.utils.CheckerItem; -import org.codechecker.eclipse.plugin.utils.CheckerItem.LAST_ACTION; /** * Global and project level preferences pages. @@ -45,9 +58,10 @@ */ public class CommonGui { - private static final String CC_BINARY = "/bin/CodeChecker"; - private static final String VALID_PACKAGE = "CodeChecker package directory is valid"; - private static final String INVALID_PACKAGE = "CodeChecker package directory is invalid"; + public static final String CC_BIN_LABEL = "CodeChecker binary:"; + public static final String VENV_LABEL = "Virtual env:"; + + private static final String VALID_PACKAGE = "CodeChecker being used: "; private static final String BROSWE = "Browse"; private static final String CHECKER_ENABLED = " -e "; private static final String CHECKER_DISABLED = " -d "; @@ -55,6 +69,7 @@ public class CommonGui { private static final int TEXTWIDTH = 200; private static final int FORM_COLUMNS = 3; + private static final int FORM_ONE_ROW = 1; private boolean globalGui;// whether this class is for global or project // specific preferences @@ -62,8 +77,20 @@ public class CommonGui { // whether to use global preferences private CcConfigurationBase config; private CodeCheckerProject cCProject; + private ICodeChecker codeChecker; + + private Button pathCc; + private Button preBuiltCc; + private Button customBuiltCc; + private Composite ccDirClient; private Text codeCheckerDirectoryField;// codechecker dir + private Button codeCheckerDirectoryFieldBrowse; + private Composite ccVenvClient; private Text pythonEnvField;// CodeChecker python env + private Button pythonEnvFieldBrowse; + private ResolutionMethodTypes currentResMethod; + + private Section checkerConfigSection; private Text numThreads;// #of analysis threads private Text cLoggers;// #C compiler commands to catch @@ -136,87 +163,31 @@ public Control createContents(final Composite parent) { layout.maxNumColumns = 1; form.getBody().setLayout(layout); + loadConfig(false); + Section globalConfigSection = null; if (!globalGui) { globalConfigSection = toolkit.createSection(form.getBody(), ExpandableComposite.EXPANDED); } - final Section checkerConfigSection = toolkit.createSection(form.getBody(), - ExpandableComposite.TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); - checkerConfigSection.setEnabled(true); - - final Composite client = toolkit.createComposite(checkerConfigSection); - client.setLayout(new GridLayout(FORM_COLUMNS, false)); - checkerConfigSection.setClient(client); - checkerConfigSection.setText("Configuration"); + Section packageSection = createConfigSection(toolkit); - codeCheckerDirectoryField = addTextField(toolkit, client, "CodeChecker package root directory", ""); - codeCheckerDirectoryField.addListener(SWT.FocusOut, new Listener() { - @Override - public void handleEvent(Event event) { - try { - Map changedConfig = getConfigFromFields(); - CodeCheckEnvironmentChecker.getCheckerEnvironment(changedConfig, - changedConfig.get(ConfigTypes.CHECKER_PATH) + CC_BINARY); - form.setMessage(VALID_PACKAGE, IMessageProvider.INFORMATION); - } catch (IllegalArgumentException e1) { - form.setMessage(INVALID_PACKAGE, IMessageProvider.ERROR); - } - } - }); - - final Button codeCheckerDirectoryFieldBrowse = new Button(client, SWT.PUSH); - codeCheckerDirectoryFieldBrowse.setText(BROSWE); - codeCheckerDirectoryFieldBrowse.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent event) { - DirectoryDialog dlg = new DirectoryDialog(client.getShell()); - dlg.setFilterPath(codeCheckerDirectoryField.getText()); - dlg.setText("Browse codechecker root"); - String dir = dlg.open(); - if (dir != null) { - codeCheckerDirectoryField.setText(dir); - try { - Map changedConfig = getConfigFromFields(); - CodeCheckEnvironmentChecker.getCheckerEnvironment(changedConfig, - changedConfig.get(ConfigTypes.CHECKER_PATH) + CC_BINARY); - form.setMessage(VALID_PACKAGE, IMessageProvider.INFORMATION); - } catch (IllegalArgumentException e1) { - form.setMessage(INVALID_PACKAGE, IMessageProvider.ERROR); - } - } - } - }); + checkerConfigSection = toolkit.createSection(form.getBody(), + ExpandableComposite.SHORT_TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); + checkerConfigSection.setEnabled(true); - pythonEnvField = addTextField(toolkit, client, "Python virtualenv root directory (optional)", ""); - final Button pythonEnvFieldBrowse = new Button(client, SWT.PUSH); - pythonEnvFieldBrowse.setText(BROSWE); - pythonEnvFieldBrowse.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent event) { - DirectoryDialog dlg = new DirectoryDialog(client.getShell()); - dlg.setFilterPath(codeCheckerDirectoryField.getText()); - dlg.setText("Browse python environment"); - String dir = dlg.open(); - if (dir != null) { - pythonEnvField.setText(dir); - } - } - }); + final Composite comp = toolkit.createComposite(checkerConfigSection); + comp.setLayout(new GridLayout(FORM_COLUMNS, false)); - numThreads = addTextField(toolkit, client, "Number of analysis threads", "4"); - toolkit.createLabel(client, ""); - cLoggers = addTextField(toolkit, client, "Compiler commands to log", "gcc:g++:clang:clang++"); - toolkit.createLabel(client, ""); + checkerConfigSection.setClient(comp); + checkerConfigSection.setText("Analysis options"); - Map configMap = loadConfig(false); - try { - CodeCheckEnvironmentChecker.getCheckerEnvironment(configMap, - configMap.get(ConfigTypes.CHECKER_PATH) + CC_BINARY); - form.setMessage(VALID_PACKAGE, IMessageProvider.INFORMATION); - } catch (IllegalArgumentException e1) { - form.setMessage(INVALID_PACKAGE, IMessageProvider.ERROR); - } + numThreads = addTextField(toolkit, comp, "Number of analysis threads", "4"); + toolkit.createLabel(comp, ""); + cLoggers = addTextField(toolkit, comp, "Compiler commands to log", "gcc:g++:clang:clang++"); + toolkit.createLabel(comp, ""); - final Button checkers = toolkit.createButton(client, "Toggle enabled checkers", SWT.PUSH); + final Button checkers = toolkit.createButton(comp, "Toggle enabled checkers", SWT.PUSH); checkers.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { @@ -226,12 +197,10 @@ public void run() { Shell activeShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); //Map config = getConfigFromFields(); try { - CodeCheckEnvironmentChecker checkerEnv = new CodeCheckEnvironmentChecker(cCProject); - ArrayList checkersList = getCheckerList(checkerEnv); + ArrayList checkersList = getCheckerList(); CheckerView dialog = new CheckerView(activeShell, checkersList); int result = dialog.open(); - if (result == 0) { checkerListArg = checkerListToCheckerListArg(dialog.getCheckersList()); } @@ -243,46 +212,212 @@ public void run() { action.run(); } }); + checkers.setData("org.eclipse.swtbot.widget.checkersKey", "checkesButton"); if (!globalGui) { - recursiveSetEnabled(checkerConfigSection, !useGlobalSettings); + recursiveSetEnabled(form.getBody(), !useGlobalSettings); final Composite client3 = toolkit.createComposite(globalConfigSection); client3.setLayout(new GridLayout(2, true)); globalConfigSection.setClient(client3); globalcc = toolkit.createButton(client3, "Use global configuration", SWT.RADIO); - globalcc.setSelection(useGlobalSettings); globalcc.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { if (globalcc.getSelection()) { recursiveSetEnabled(checkerConfigSection, false); + recursiveSetEnabled(packageSection, false); useGlobalSettings = true; config = cCProject.getGlobal(); - setFields(config.get()); + setFields(); + locateCodeChecker(); } } }); + globalcc.setSelection(useGlobalSettings); projectcc = toolkit.createButton(client3, "Use project configuration", SWT.RADIO); - projectcc.setSelection(!useGlobalSettings); projectcc.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { if (projectcc.getSelection()) { recursiveSetEnabled(checkerConfigSection, true); + recursiveSetEnabled(packageSection, true); useGlobalSettings = false; config = cCProject.getLocal(); - setFields(config.get()); + setFields(); + changeDirectoryInputs(); + locateCodeChecker(); } } }); - + projectcc.setSelection(!useGlobalSettings); + changeDirectoryInputs(); } + setFields(); + locateCodeChecker(); return form.getBody(); } - /** - * Recursive control state modifier. - * If the control is {@link Composite} toggles it state and all of it's children {@link Control}. - * @param control The parent control. - * @param b The state to be set. - */ + /** + * Creates the resolution method group, and the package directory inputs. + * + * @param toolkit + * The toolkit to be used. + * @return The encapsulating Section. + */ + private Section createConfigSection(FormToolkit toolkit) { + + final Section packageConfigSection = toolkit.createSection(form.getBody(), + ExpandableComposite.SHORT_TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); + packageConfigSection.setEnabled(true); + + final Composite client = toolkit.createComposite(packageConfigSection); + client.setLayout(new GridLayout(FORM_COLUMNS, false)); + + packageConfigSection.setClient(client); + packageConfigSection.setText("Configuration"); + + Group resolutionType = new Group(client, SWT.NULL); + resolutionType.setText("CodeChecker resolution method."); + GridLayoutFactory.fillDefaults().numColumns(1).applyTo(resolutionType); + GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER) + .span(FORM_COLUMNS, FORM_ONE_ROW).applyTo(resolutionType); + resolutionType.setBackground(client.getBackground()); + + ccDirClient = toolkit.createComposite(client); + GridLayoutFactory.fillDefaults().numColumns(FORM_COLUMNS).applyTo(ccDirClient); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(FORM_COLUMNS, FORM_ONE_ROW) + .applyTo(ccDirClient); + ccDirClient.setBackground(client.getBackground()); + + ccVenvClient = toolkit.createComposite(client); + GridLayoutFactory.fillDefaults().numColumns(FORM_COLUMNS).applyTo(ccVenvClient); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(FORM_COLUMNS, FORM_ONE_ROW) + .applyTo(ccVenvClient); + ccVenvClient.setBackground(client.getBackground()); + + pathCc = toolkit.createButton(resolutionType, "Search in PATH", SWT.RADIO); + pathCc.setData(ResolutionMethodTypes.PATH); + pathCc.addSelectionListener(new PackageResolutionSelectionAdapter()); + + preBuiltCc = toolkit.createButton(resolutionType, "Pre built package", SWT.RADIO); + preBuiltCc.setData(ResolutionMethodTypes.PRE); + preBuiltCc.addSelectionListener(new PackageResolutionSelectionAdapter()); + + customBuiltCc = toolkit.createButton(resolutionType, "Custom built package", SWT.RADIO); + customBuiltCc.setData(ResolutionMethodTypes.PY); + customBuiltCc.addSelectionListener(new PackageResolutionSelectionAdapter()); + + codeCheckerDirectoryField = addTextField(toolkit, ccDirClient, CC_BIN_LABEL, ""); + codeCheckerDirectoryField.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + locateCodeChecker(); + } + }); + + codeCheckerDirectoryFieldBrowse = new Button(ccDirClient, SWT.PUSH); + codeCheckerDirectoryFieldBrowse.setText(BROSWE); + codeCheckerDirectoryFieldBrowse.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + FileDialog dlg = new FileDialog(client.getShell()); + dlg.setFilterPath(codeCheckerDirectoryField.getText()); + dlg.setText("Browse CodeChecker binary"); + String dir = dlg.open(); + if (dir != null) { + codeCheckerDirectoryField.setText(dir); + locateCodeChecker(); + } + } + }); + + pythonEnvField = addTextField(toolkit, ccVenvClient, VENV_LABEL, ""); + pythonEnvField.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + locateCodeChecker(); + } + }); + pythonEnvFieldBrowse = new Button(ccVenvClient, SWT.PUSH); + pythonEnvFieldBrowse.setText(BROSWE); + pythonEnvFieldBrowse.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + DirectoryDialog dlg = new DirectoryDialog(client.getShell()); + dlg.setFilterPath(codeCheckerDirectoryField.getText()); + dlg.setText("Browse python environment"); + String dir = dlg.open(); + if (dir != null) { + pythonEnvField.setText(dir); + locateCodeChecker(); + } + } + }); + changeDirectoryInputs(); + return packageConfigSection; + + } + + /** + * Changes directory input widgets depending on the resolution method radio + * group. + */ + public void changeDirectoryInputs() { + if (!useGlobalSettings) + switch (currentResMethod) { + case PATH: + recursiveSetEnabled(ccDirClient, false); + recursiveSetEnabled(ccVenvClient, false); + break; + case PRE: + recursiveSetEnabled(ccDirClient, true); + recursiveSetEnabled(ccVenvClient, false); + break; + case PY: + recursiveSetEnabled(ccDirClient, true); + recursiveSetEnabled(ccVenvClient, true); + break; + default: + break; + } + } + + /** + * Tries to find a CodeChecker package. + */ + public void locateCodeChecker() { + CodeCheckerLocatorService serv = null; + switch (currentResMethod) { + case PATH: + serv = new EnvCodeCheckerLocatorService(); + break; + case PRE: + serv = new PreBuiltCodeCheckerLocatorService(); + break; + case PY: + serv = new CustomBuiltCodeCheckerLocatorService(); + break; + default: + break; + } + ICodeChecker cc = null; + try { + cc = serv.findCodeChecker(Paths.get(codeCheckerDirectoryField.getText()), + Paths.get(pythonEnvField.getText()), new CodeCheckerFactory(), new ShellExecutorHelperFactory()); + form.setMessage(VALID_PACKAGE + cc.getLocation().toString(), IMessageProvider.INFORMATION); + if (globalGui || (!globalGui && !useGlobalSettings)) + recursiveSetEnabled(checkerConfigSection, true); + } catch (InvalidCodeCheckerException | IllegalArgumentException | ArrayIndexOutOfBoundsException e) { + recursiveSetEnabled(checkerConfigSection, false); + form.setMessage(e.getMessage(), IMessageProvider.ERROR); + } + this.codeChecker = cc; + } + + /** + * Recursive control state modifier. If the control is {@link Composite} toggles + * it state and all of it's children {@link Control}. + * + * @param control + * The parent control. + * @param b + * The state to be set. + */ public void recursiveSetEnabled(Control control, Boolean b) { if (control instanceof Composite) { Composite comp = (Composite) control; @@ -295,14 +430,13 @@ public void recursiveSetEnabled(Control control, Boolean b) { /** * Returns The all checkers from CodeChecker. - * @param ccec The Environment Checker to be used. * @return A list of all available checkers. */ - private ArrayList getCheckerList(CodeCheckEnvironmentChecker ccec) { + private ArrayList getCheckerList() { // ArrayList defaultCheckersList = new ArrayList<>(); ArrayList checkersList = new ArrayList<>(); // // new Checkers List - String s = ccec.getCheckerList(); + String s = codeChecker.getCheckers(); String[] newCheckersSplit = s.split("\n"); // old Checkers Command //String[] checkersCommand = checkerListArg.split(CHECKER_SEPARATOR); @@ -360,16 +494,30 @@ public Map loadConfig(boolean resetToDefault) { ret = config.get(); } else ret = config.getDefaultConfig(); - - setFields(ret); + currentResMethod = ResolutionMethodTypes.getFromString(config.get(ConfigTypes.RES_METHOD)); return ret; } /** * Sets the form fields with the given config maps values. - * @param config The config which values are taken. */ - public void setFields(Map config) { + public void setFields() { + pathCc.setSelection(false); + preBuiltCc.setSelection(false); + customBuiltCc.setSelection(false); + switch (currentResMethod) { + case PATH: + pathCc.setSelection(true); + break; + case PRE: + preBuiltCc.setSelection(true); + break; + case PY: + customBuiltCc.setSelection(true); + break; + default: + break; + } codeCheckerDirectoryField.setText(config.get(ConfigTypes.CHECKER_PATH)); pythonEnvField.setText(config.get(ConfigTypes.PYTHON_PATH)); checkerListArg = config.get(ConfigTypes.CHECKER_LIST); @@ -401,6 +549,8 @@ public void saveConfig() { conf.put(ConfigTypes.CHECKER_LIST, checkerListArg); conf.put(ConfigTypes.ANAL_THREADS, numThreads.getText()); conf.put(ConfigTypes.COMPILERS, cLoggers.getText()); + conf.put(ConfigTypes.RES_METHOD, currentResMethod.toString()); + config.setCodeChecker(codeChecker); config.update(conf); if(!globalGui) cCProject.useGlobal(useGlobalSettings); @@ -437,4 +587,19 @@ public void init(IWorkbench workbench) { // TODO Auto-generated method stub } + /** + * Callback for the Resolution method selection listener. + */ + private class PackageResolutionSelectionAdapter extends SelectionAdapter { + @Override + public void widgetSelected(SelectionEvent event) { + boolean isSelected = ((Button) event.getSource()).getSelection(); + if (isSelected) { + currentResMethod = (ResolutionMethodTypes) event.widget.getData(); + changeDirectoryInputs(); + locateCodeChecker(); + } + } + + } } diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/Config.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/Config.java index a60d3c55..b47ca1c0 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/Config.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/Config.java @@ -5,9 +5,8 @@ import java.util.Map; import java.util.Set; -import org.eclipse.core.runtime.IStatus; - import org.codechecker.eclipse.plugin.Logger; +import org.eclipse.core.runtime.IStatus; /** * Classes for handling actual configuration entries, and logging. @@ -24,6 +23,7 @@ public enum ConfigTypes { // Common configuration values CHECKER_PATH("codechecker_path"), PYTHON_PATH(""), + RES_METHOD("PATH"), COMPILERS("gcc:g++:clang:clang++"), ANAL_THREADS("4"), CHECKER_LIST("enabled_checkers"), diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/project/CodeCheckerProject.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/project/CodeCheckerProject.java index cfe12121..b2e02002 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/project/CodeCheckerProject.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/config/project/CodeCheckerProject.java @@ -94,12 +94,19 @@ private void setEnvironment() { environmentVariables.put(ev, ev.getDefaultValue()); } String checkerDir = current.get(ConfigTypes.CHECKER_PATH); + String checkerRootDir = ""; + try { + checkerRootDir = Paths.get(checkerDir).getParent().getParent().toAbsolutePath().toString(); + } catch (NullPointerException e) { + checkerRootDir = checkerDir; + } + environmentVariables.put(EnvironmentVariables.LD_LIBRARY_PATH, - checkerDir + EnvironmentVariables.LD_LIBRARY_PATH.getDefaultValue()); + checkerRootDir + EnvironmentVariables.LD_LIBRARY_PATH.getDefaultValue()); environmentVariables.put(EnvironmentVariables._, checkerDir + EnvironmentVariables._.getDefaultValue()); environmentVariables.put(EnvironmentVariables.CC_LOGGER_BIN, - checkerDir + EnvironmentVariables.CC_LOGGER_BIN.getDefaultValue()); + checkerRootDir + EnvironmentVariables.CC_LOGGER_BIN.getDefaultValue()); environmentVariables.put(EnvironmentVariables.CC_LOGGER_GCC_LIKE, current.get(ConfigTypes.COMPILERS)); // The current path to workspace is always handled by this project. diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/report/job/AnalyzeJob.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/report/job/AnalyzeJob.java index 81e00d2e..33214510 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/report/job/AnalyzeJob.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/report/job/AnalyzeJob.java @@ -1,33 +1,31 @@ package org.codechecker.eclipse.plugin.report.job; -import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import org.codechecker.eclipse.plugin.Logger; +import org.codechecker.eclipse.plugin.config.CcConfigurationBase; +import org.codechecker.eclipse.plugin.config.CodeCheckerContext; +import org.codechecker.eclipse.plugin.config.project.CodeCheckerProject; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import com.google.common.base.Optional; - -import org.codechecker.eclipse.plugin.Logger; -import org.codechecker.eclipse.plugin.config.CodeCheckerContext; -import org.codechecker.eclipse.plugin.runtime.CodeCheckEnvironmentChecker; - /** * This class represents a CodeChecker analyze command. * */ public class AnalyzeJob extends Job { - private IProject project; - private CodeCheckEnvironmentChecker ccec; - + private CodeCheckerProject project; + private CcConfigurationBase config; + private Path logFile; /** * Hidden due analyze is meaningless without a project. * @param name unused. @@ -42,51 +40,64 @@ private AnalyzeJob(String name) { */ public AnalyzeJob(IProject project) { super("Running CodeChecker Analyze"); - this.project = project; - ccec = new CodeCheckEnvironmentChecker( - CodeCheckerContext.getInstance().getCcProject(project)); + this.project = CodeCheckerContext.getInstance().getCcProject(project); + config = this.project.getCurrentConfig(); } @Override protected IStatus run(IProgressMonitor monitor) { Logger.log(IStatus.INFO, "Running AnalyzeJob"); - - Optional analyzeLog = moveLogFile(); - if(analyzeLog.isPresent()) { - AtomicInteger taskCount = new AtomicInteger(0); - try { - //read the file - Files.lines(Paths.get(analyzeLog.get())).forEach(new Consumer() { + try { + copyLogFile(); + } catch (IOException e) { + Logger.log(IStatus.ERROR, "Couldn't copy logfile!"); + } - @Override - public void accept(String t) { - if ( t.contains("\"command\":")){ - taskCount.incrementAndGet(); - } + AtomicInteger taskCount = new AtomicInteger(0); + + // read the file + try { + Files.lines(logFile).forEach(new Consumer() { + + @Override + public void accept(String t) { + if (t.contains("\"command\":")) { + taskCount.incrementAndGet(); } - }); - } catch (IOException e) { - // isPresent() should render this unneeded. - } - monitor.beginTask("Starting Analysis...", taskCount.get()*2); - ccec.processLog(analyzeLog.get(), true, monitor, taskCount.get()*2); + } + }); + } catch (IOException e) { + Logger.log(IStatus.ERROR, "Couldn't read logFile!"); } + + monitor.beginTask("Starting Analysis...", taskCount.get() * 2); + config.getCodeChecker().analyze(logFile, true, monitor, taskCount.get() * 2, config); + + deleteLogFile(); return Status.OK_STATUS; } /** - * Renames the logfile, to avoid concurrency issues. - * @return The path to the temporary logfile wrapped in an {@link Optional}. + * Creates a copy of the log file created by ld logger, to avoid concurrency + * issues. + * + * @throws IOException + * Thrown when the copying fails. */ - private Optional moveLogFile() { - String filename = CodeCheckerContext.getInstance().getCcProject(project).getLogFileLocation().toString(); - File f = new File(filename); - if (f.exists()) { - String newName = filename + System.nanoTime(); - f.renameTo(new File(newName)); + private void copyLogFile() throws IOException { + Path originalLogFile = project.getLogFileLocation(); + logFile = Paths.get(originalLogFile.toAbsolutePath().toString() + System.nanoTime()); + Files.copy(originalLogFile, logFile); + } - return Optional.of(newName); + /** + * Delete the temporary logfile after the analysis. + */ + public void deleteLogFile() { + try { + Files.delete(logFile); + } catch (IOException e) { + Logger.log(IStatus.ERROR, "Couldn't delete the temporary log file!"); } - return Optional.absent(); } } diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckEnvironmentChecker.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckEnvironmentChecker.java deleted file mode 100644 index 8d43c481..00000000 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckEnvironmentChecker.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.codechecker.eclipse.plugin.runtime; - -import java.io.File; -import java.util.Map; - -import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; -import org.codechecker.eclipse.plugin.config.global.CcGlobalConfiguration; -import org.codechecker.eclipse.plugin.config.project.CodeCheckerProject; -import org.eclipse.core.runtime.IProgressMonitor; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableMap; - - -/** - * This class checks for Environments used by CodeChecker. - * - */ -public class CodeCheckEnvironmentChecker { - - public final Optional pythonEnvironment; - public final String checkerDir; // root directory of CodeChecker - public final String codeCheckerCommand; // CodecCheker executable path - private Map config; - private CodeCheckerProject project; - private String checkerList; - - //with specific python. This - // can be used to run CodeChecker - public final ImmutableMap environmentBefore; - - /** - * - * @param project - * The project that will be used for constructing the Environment - * checker. - */ - public CodeCheckEnvironmentChecker(CodeCheckerProject project) { - this.project = project; - if (project != null) - config = project.getCurrentConfig().get(); - // This is bad design, but until further refactoring it should do. - else - config = CcGlobalConfiguration.getInstance().get(); - - if (!config.containsKey(ConfigTypes.PYTHON_PATH) - || (config.containsKey(ConfigTypes.PYTHON_PATH) && config.get(ConfigTypes.PYTHON_PATH).isEmpty())){ - pythonEnvironment=Optional.absent(); - SLogger.log(LogI.INFO, "pythonenv is not set"); - } - else{ - SLogger.log(LogI.INFO, "pythonenv is set to:"+config.get("PYTHON_PATH")); - pythonEnvironment=Optional.of(config.get(ConfigTypes.PYTHON_PATH)); - } - - //checkerList=getConfigValue(ConfigTypes.CHECKER_LIST); - checkerDir=getConfigValue(ConfigTypes.CHECKER_PATH); - environmentBefore = getInitialEnvironment(pythonEnvironment); - codeCheckerCommand = checkerDir+"/bin/CodeChecker"; - } - - /** - * @return The Config thats used in the CodeCheckEnvironmentChecker. - */ - public Map getConfig() { - return config; - } - - /** - * @param key - * The config key for the interesting value. - * @return The value for the key or an empty String if it can't be found. - */ - private String getConfigValue(ConfigTypes key) { - if (config.containsKey(key)) - return config.get(key); - else - return ""; - } - - /** - * Checks if the given path to CodeChecker is valid. - * @param config The Configuration to be used, - * populated with {@link ConfigTypes}. - * @param codeCheckerBinaryPath Path to CodeChecker. - */ - public static void getCheckerEnvironment( - Map config, String codeCheckerBinaryPath) { - - ShellExecutorHelper she = new ShellExecutorHelper( - getInitialEnvironment(Optional.of(config.get(ConfigTypes.PYTHON_PATH)))); - - String cmd=codeCheckerBinaryPath + " -h"; - SLogger.log(LogI.INFO, "Testing " + cmd); - Optional ccEnvOutput = she.quickReturnOutput(cmd); - double test = 0; - // WTF - while(!ccEnvOutput.isPresent() && test <= 2){ - ccEnvOutput = she.quickReturnOutput(cmd, Math.pow( 2.0 , test ) * 1000); - ++test; - } - if (!ccEnvOutput.isPresent()) { - SLogger.log(LogI.ERROR, "Cannot run CodeChecker command:"+cmd); - throw new IllegalArgumentException("Couldn't run the specified CodeChecker for " + - "environment testing!"); - } - } - - /** - * Returns new environment if using Python virtual environment or System env if not. - * @param pythonEnvironment Path to Python virtual environment activator. - * @return The environment to be used. - */ - private static ImmutableMap getInitialEnvironment(Optional pythonEnvironment) { - if (pythonEnvironment.isPresent()) { - ShellExecutorHelper she = new ShellExecutorHelper(System.getenv()); - - Optional output = she.quickReturnOutput("source " + pythonEnvironment.get() + "/bin/activate" + - " ; env"); - if (!output.isPresent()) { - SLogger.log(LogI.INFO, "SERVER_GUI_MSG >> Couldn't check the given python environment!"); - throw new IllegalArgumentException("Couldn't check the given python environment!"); - } else { - ImmutableMap environment = (new EnvironmentParser()).parse(output - .get()); - return environment; - } - - } else { - SLogger.log(LogI.INFO, "Python Env not specified. Using original system env."); - return ImmutableMap.copyOf(System.getenv()); - } - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (obj.getClass() != getClass()) { - return false; - } - CodeCheckEnvironmentChecker other = (CodeCheckEnvironmentChecker) obj; - return this.config.equals(other.getConfig()); - } - - public void setCheckerList(String list) { - this.checkerList = list; - } - - /** - * Creates a Codechecker analyze command. - * @param buildLog Path to the compile commands file, which the analyze command uses. - * @return The constructed analyze command. - */ - public String createAnalyzeCommmand(String buildLog){ - return codeCheckerCommand + " analyze " + getConfigValue(ConfigTypes.CHECKER_LIST) + - " -j "+ getConfigValue(ConfigTypes.ANAL_THREADS) + " -n javarunner" + - " -o "+ project.getLogFileLocation().getParent().toString() +"/results/ " + buildLog; - } - - /** - * Executes CodeChecker check command - * on the build log received in the fileName parameter. - * @param fileName Build log in the http://clang.llvm.org/docs/JSONCompilationDatabase.html format. - * @param logToConsole Flag for indicating console logging - * @param monitor ProgressMonitor for to be able to increment progress bar. - * @param taskCount How many analyze step to be taken. - * @return CodeChecker check command output - */ - public String processLog(String fileName, boolean logToConsole, IProgressMonitor monitor, int taskCount) { - ShellExecutorHelper she = new ShellExecutorHelper(environmentBefore); - String cmd = createAnalyzeCommmand(fileName); - - SLogger.log(LogI.INFO, "SERVER_SER_MSG >> processLog >> "+ cmd); - //Optional ccOutput = she.waitReturnOutput(cmd,logToConsole); - Optional ccOutput = she.progressableWaitReturnOutput(cmd,logToConsole, monitor, taskCount); - if (ccOutput.isPresent()) { - // assume it succeeded, and delete the log file... - File f = new File(fileName); - f.delete(); - } - return ccOutput.or(""); - } - - public String getCheckerList() { - ShellExecutorHelper she = new ShellExecutorHelper(environmentBefore); - String cmd = codeCheckerCommand + " checkers"; - Optional ccOutput = she.waitReturnOutput(cmd,false); - return ccOutput.or(""); - } -} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocator.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocator.java deleted file mode 100644 index e49d9bba..00000000 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocator.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.codechecker.eclipse.plugin.runtime; - -import com.google.common.base.Optional; - -import java.io.IOException; - -/** - * Locates a local CodeChecker installation. - * Either the CodeChecker executable is in the path, or the class is - * initialized with a path to the CodeChecker package root directory. - */ -public class CodeCheckerLocator { - - // Linux-specific path to CodeChecker executable in PATH - private final Optional systemCcExecutable; - // Linux-specific CodeChecker executable in CodeChecker package directory - // given by the user on the configuration panel - private final Optional customCcExecutable; - private ShellExecutorHelper shellExecutor; // TODO: inject? - - public CodeCheckerLocator(ShellExecutorHelper executor, Optional customCcExecutable) - throws IOException { - this.shellExecutor = executor; - this.systemCcExecutable = locateSystemCodeChecker(); - this.customCcExecutable = customCcExecutable; - } - - public Optional getRunnerCommand() { - return customCcExecutable.or(systemCcExecutable); - } - - public boolean foundCcExecutable() { - return customCcExecutable.isPresent() || systemCcExecutable.isPresent(); - } - - private Optional locateSystemCodeChecker() { - return shellExecutor.quickReturnFirstLine("/usr/bin/which CodeChecker"); - } - -} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParser.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParser.java deleted file mode 100644 index c59d77b5..00000000 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParser.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.codechecker.eclipse.plugin.runtime; - -import com.google.common.collect.ImmutableMap; - -/** - * Parses the output of /usr/bin/env into a String map - */ -public class EnvironmentParser { - - public ImmutableMap parse(String envOutput) { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - - for (String line : envOutput.split("\n")) { - String[] entry = line.trim().split("=", 2); - if (entry.length == 2) { - builder.put(entry[0], entry[1]); - } - } - - return builder.build(); - } -} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/IShellExecutorHelperFactory.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/IShellExecutorHelperFactory.java new file mode 100644 index 00000000..d68dbf6f --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/IShellExecutorHelperFactory.java @@ -0,0 +1,17 @@ +package org.codechecker.eclipse.plugin.runtime; + +import java.util.Map; + +/** + * Interface for {@link ShellExecutorHelper} factory. + */ +public interface IShellExecutorHelperFactory { + /** + * Method for creating {@link ShellExecutorHelper}. + * + * @param env + * An environment to be used with the ShellExecutorHelper. + * @return A {@link ShellExecutorHelper} instance. + */ + public ShellExecutorHelper createShellExecutorHelper(Map env); +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/ShellExecutorHelperFactory.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/ShellExecutorHelperFactory.java new file mode 100644 index 00000000..4115a6fe --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/ShellExecutorHelperFactory.java @@ -0,0 +1,15 @@ +package org.codechecker.eclipse.plugin.runtime; + +import java.util.Map; + +/** + * Implementation of {@link IShellExecutorHelperFactory}. + */ +public class ShellExecutorHelperFactory implements IShellExecutorHelperFactory { + + @Override + public ShellExecutorHelper createShellExecutorHelper(Map env) { + return new ShellExecutorHelper(env); + } + +} diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/package-info.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/package-info.java new file mode 100644 index 00000000..c5c172a9 --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/runtime/package-info.java @@ -0,0 +1,4 @@ +/** + * Command line related package. + */ +package org.codechecker.eclipse.plugin.runtime; \ No newline at end of file diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocatorTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocatorTest.java deleted file mode 100644 index c806b47b..00000000 --- a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/CodeCheckerLocatorTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.codechecker.eclipse.plugin.runtime; - -import com.google.common.base.Optional; - -import org.codechecker.eclipse.plugin.runtime.CodeCheckerLocator; -import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; - -import org.junit.Test; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class CodeCheckerLocatorTest { - - @Test - public void noSystemLocatorWithoutEnv() throws IOException { - CodeCheckerLocator onlySystemLocatorWithoutEnv = new CodeCheckerLocator(new - ShellExecutorHelper(new HashMap()), Optional.absent()); - assertThat(onlySystemLocatorWithoutEnv.foundCcExecutable(), is(false)); - assertThat(onlySystemLocatorWithoutEnv.getRunnerCommand(), is(equalTo(Optional - .absent()))); - } - - /*@Test - public void findsInPath() throws IOException { - CodeCheckerLocator onlySystemLocatorWithEnv = new CodeCheckerLocator(new - ShellExecutorHelper(envWithPath(getExecutorDirectoryLocation("usage"))), Optional - .absent()); - assertThat(onlySystemLocatorWithEnv.foundCcExecutable(), is(true)); - assertThat(onlySystemLocatorWithEnv.getRunnerCommand(), is(equalTo(Optional.of - (getExecutorLocation("usage"))))); - }*/ - - /* @Test - public void findsSpecificLocatorWithSh() throws IOException { - CodeCheckerLocator specificLocator = new CodeCheckerLocator(new ShellExecutorHelper(new - HashMap()), Optional.of(getExecutorInitScriptLocation("usage"))); - assertThat(specificLocator.foundCcExecutable(), is(true)); - assertThat(specificLocator.getRunnerCommand(), is(equalTo(Optional.of("source " + - getExecutorInitScriptLocation("usage") + "; CodeChecker")))); - }*. - - /*@Test - public void findsSpecificLocatorWithDirectory() throws IOException { - CodeCheckerLocator specificLocator = new CodeCheckerLocator(new ShellExecutorHelper(new - HashMap()), Optional.of(getExecutorDirectoryLocation("usage"))); - assertThat(specificLocator.foundCcExecutable(), is(true)); - assertThat(specificLocator.getRunnerCommand(), is(equalTo(Optional.of("source " + - getExecutorInitScriptLocation("usage") + "; CodeChecker")))); - }*/ - - /* @Test - public void preferSpecificLocator() throws IOException { - CodeCheckerLocator specificLocator = new CodeCheckerLocator(new ShellExecutorHelper - (envWithPath(getExecutorDirectoryLocation("usage"))), Optional.of - (getExecutorDirectoryLocation("usage"))); - assertThat(specificLocator.foundCcExecutable(), is(true)); - assertThat(specificLocator.getRunnerCommand(), is(equalTo(Optional.of("source " + - getExecutorInitScriptLocation("usage") + "; CodeChecker")))); - }*/ - - /* @Test - public void handlesBadSpecificLocator() throws IOException { - CodeCheckerLocator specificLocator = new CodeCheckerLocator(new ShellExecutorHelper(new - HashMap()), Optional.of(getExecutorInitScriptLocation - ("bad-usage"))); - assertThat(specificLocator.foundCcExecutable(), is(false)); - assertThat(specificLocator.getRunnerCommand(), is(equalTo(Optional.absent()))); - }*/ - - /*@Test - public void findsSystemWithBadSpecific() throws IOException { - CodeCheckerLocator specificLocator = new CodeCheckerLocator(new ShellExecutorHelper - (envWithPath(getExecutorDirectoryLocation("usage"))), Optional.of - (getExecutorDirectoryLocation("bad-usage"))); - assertThat(specificLocator.foundCcExecutable(), is(true)); - assertThat(specificLocator.getRunnerCommand(), is(equalTo(Optional.of(getExecutorLocation - ("usage"))))); - }*/ - - private String getExecutorDirectoryLocation(String name) { - return getClass().getResource("/mock-codechecker/").getPath() + name; - } - - private String getExecutorInitScriptLocation(String name) { - return getExecutorDirectoryLocation(name) + "/init/init.sh"; - } - - private String getExecutorLocation(String name) { - return getExecutorDirectoryLocation(name) + "/CodeChecker"; - } - - private Map envWithPath(String path) { - HashMap hm = new HashMap(); - hm.put("PATH", path); - - return hm; - } - -} diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParserTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParserTest.java deleted file mode 100644 index c68297ac..00000000 --- a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/runtime/EnvironmentParserTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.codechecker.eclipse.plugin.runtime; - -import com.google.common.collect.ImmutableMap; - -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import org.codechecker.eclipse.plugin.runtime.EnvironmentParser; - -public class EnvironmentParserTest { - - @Test - public void testOneLine() { - EnvironmentParser ep = new EnvironmentParser(); - ImmutableMap result = ep.parse("ALMA=korte"); - assertThat(result.containsKey("ALMA"), is(true)); - assertThat(result.get("ALMA"), is(equalTo("korte"))); - } - - @Test - public void testTwoLine() { - EnvironmentParser ep = new EnvironmentParser(); - ImmutableMap result = ep.parse("ALMA=korte\nBARACK=nemalma"); - assertThat(result.containsKey("ALMA"), is(true)); - assertThat(result.get("ALMA"), is(equalTo("korte"))); - assertThat(result.containsKey("BARACK"), is(true)); - assertThat(result.get("BARACK"), is(equalTo("nemalma"))); - } -} From b11dcf810030981781ef6b1534d18ad7bc8362eb Mon Sep 17 00:00:00 2001 From: Vodorok Date: Tue, 23 Jul 2019 16:22:20 +0200 Subject: [PATCH 2/4] Add tests for resolution logic New Unit tests and extended Integration tests. The CodeChecker class, and the locator logic is tested for PATH and Pre built package resolution. This is the same for the Integration tests, so only these two are tested. The Custom built CodeChecker package with virtual env needs a virtual environment emulation, which is not implemented yet. --- checkstyle.xml | 2 +- mavendeps/pom.xml | 1 + .../org.codechecker.eclipse.target.target | 1 + .../META-INF/MANIFEST.MF | 3 +- .../eclipse/plugin/IndicatorTest.java | 83 ++++++++++-- .../eclipse/plugin/utils/GuiUtils.java | 79 +++++++++-- .../META-INF/MANIFEST.MF | 4 +- .../plugin/codechecker/CodeCheckerTest.java | 126 ++++++++++++++++++ .../locator/CodeCheckerLocatorTest.java | 112 ++++++++++++++++ .../codechecker/locator/package-info.java | 4 + .../plugin/codechecker/package-info.java | 4 + 11 files changed, 393 insertions(+), 26 deletions(-) create mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java create mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java create mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java create mode 100644 tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/package-info.java diff --git a/checkstyle.xml b/checkstyle.xml index e527b198..3af1dd9d 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -9,7 +9,7 @@ - + diff --git a/mavendeps/pom.xml b/mavendeps/pom.xml index 00f8cdf4..58757309 100644 --- a/mavendeps/pom.xml +++ b/mavendeps/pom.xml @@ -20,6 +20,7 @@ javax.xml.parsers:jaxp-api:1.4.5 + com.github.stefanbirkner:system-rules:1.19.0 com.google.code.gson:gson:2.3.1 com.googlecode.plist:dd-plist:1.21 com.google.guava:guava:26.0-jre diff --git a/releng/org.codechecker.eclipse.target/org.codechecker.eclipse.target.target b/releng/org.codechecker.eclipse.target/org.codechecker.eclipse.target.target index d512e166..5edeb7f7 100644 --- a/releng/org.codechecker.eclipse.target/org.codechecker.eclipse.target.target +++ b/releng/org.codechecker.eclipse.target/org.codechecker.eclipse.target.target @@ -21,6 +21,7 @@ + diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/META-INF/MANIFEST.MF b/tests/org.codechecker.eclipse.rcp.it.tests/META-INF/MANIFEST.MF index a76b2877..53029831 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/META-INF/MANIFEST.MF +++ b/tests/org.codechecker.eclipse.rcp.it.tests/META-INF/MANIFEST.MF @@ -12,4 +12,5 @@ Require-Bundle: org.junit;bundle-version="4.12.0", org.eclipse.swtbot.junit4_x;bundle-version="2.7.0", org.eclipse.swtbot.swt.finder;bundle-version="2.7.0", org.eclipse.swtbot.eclipse.finder;bundle-version="2.7.0", - org.codechecker.eclipse.rcp.shared;bundle-version="1.0.0" + org.codechecker.eclipse.rcp.shared;bundle-version="1.0.0", + com.github.stefanbirkner.system-rules;bundle-version="1.19.0" diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java index d2918f5b..31413824 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java +++ b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java @@ -1,19 +1,23 @@ package org.codechecker.eclipse.plugin; import java.nio.file.Path; +import java.nio.file.Paths; +import org.codechecker.eclipse.plugin.codechecker.locator.EnvCodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.PreBuiltCodeCheckerLocatorService; +import org.codechecker.eclipse.plugin.codechecker.locator.ResolutionMethodTypes; import org.codechecker.eclipse.plugin.utils.GuiUtils; import org.codechecker.eclipse.rcp.shared.utils.Utils; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; import org.eclipse.swtbot.swt.finder.widgets.SWTBotCLabel; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; -import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.rules.ExpectedException; import static org.hamcrest.CoreMatchers.is; @@ -27,12 +31,20 @@ public class IndicatorTest { private static final int SHORT_WAIT_TIME = 500; // in milliseconds private static final String CODECHECKER = "CodeChecker"; + private static final String FORM_MESSAGE_CC_FOUND = "CodeChecker being used:"; + private static final String ENV_PATH = "PATH"; + private static final Path DUMMY = Paths.get("/home"); + + private static final String ERROR_NO_VALID_CC = "There was no valid CodeChecker message displayed"; private static SWTWorkbenchBot bot; @Rule public ExpectedException thrown = ExpectedException.none(); + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + private SWTBotShell preferencesShell; /** @@ -53,43 +65,90 @@ public void openPreferences() { } /** - * Test that with unconfigured CodeChecker, a warning message is displayed. + * Test that with path option selected, the proper warning message is displayed. */ @Test - public void testNoCodeCheckerFound() { + public void testNoCodeCheckerFoundInPath() { SWTBotCLabel label = null; try { - label = bot.clabel("CodeChecker package directory is invalid"); + label = bot.clabel(EnvCodeCheckerLocatorService.ERROR); } catch (WidgetNotFoundException e) { System.out.println(e.getMessage()); } - assertThat("There was no invalid CodeChecker message displayed", label, is(IsNull.notNullValue())); + assertThat(ERROR_NO_VALID_CC, label, is(IsNull.notNullValue())); preferencesShell.close(); } + /** + * Test that with prebuilt option selected, the proper warning message is + * displayed. + */ + @Test + public void testNoCodeCheckerFoundPre() { + GuiUtils.setCCBinDir(ResolutionMethodTypes.PRE, DUMMY, bot, false); + + SWTBotCLabel label = null; + try { + label = bot.clabel(PreBuiltCodeCheckerLocatorService.ERROR); + } catch (WidgetNotFoundException e) { + System.out.println(e.getMessage()); + } + assertThat(ERROR_NO_VALID_CC, label, is(IsNull.notNullValue())); + + preferencesShell.close(); + } + /** * Test that with CodeChecker configured, a confirmation message is displayed. */ @Test public void testCodeCheckerFound() { Path ccDir = Utils.prepareCodeChecker(); - - SWTBotText text = bot.textWithLabel("CodeChecker package root directory"); - text.setText(ccDir.toString()); - text.setFocus(); - bot.textWithLabel("Python virtualenv root directory (optional)").setFocus(); + GuiUtils.setCCBinDir(ccDir, bot); bot.sleep(SHORT_WAIT_TIME); SWTBotCLabel label = null; try { - label = bot.clabel("CodeChecker package directory is valid"); + label = new SWTBotCLabel(GuiUtils.findCLabel(FORM_MESSAGE_CC_FOUND, bot)); } catch (WidgetNotFoundException e) { System.out.println(e.getMessage()); } - assertThat("There was no valid CodeChecker message displayed", label, is(IsNull.notNullValue())); + assertThat(ERROR_NO_VALID_CC, label, is(IsNull.notNullValue())); preferencesShell.close(); } + + /** + * Test that with CodeChecker added to PATH environment variable, the Plugin + * picks it up as a valid package and a confirmation message is displayed. + */ + @Test + public void testCodeCheckerFoundInPath() { + GuiUtils.applyClosePreferences(preferencesShell, bot); + Path ccDir = Utils.prepareCodeChecker(); + + // prepare PATH envval + String origPath = System.getenv(ENV_PATH); + String newPath = origPath.concat(":" + ccDir.toAbsolutePath().toString() + "/bin/"); + + // Set the prepared PATH + environmentVariables.set(ENV_PATH, newPath); + + preferencesShell = GuiUtils.getPreferencesTab(CODECHECKER, bot); + GuiUtils.setCCBinDir(ResolutionMethodTypes.PATH, null, bot, false); + SWTBotCLabel label = null; + try { + label = new SWTBotCLabel(GuiUtils.findCLabel(FORM_MESSAGE_CC_FOUND, bot)); + } catch (WidgetNotFoundException e) { + System.out.println(e.getMessage()); + } + assertThat(ERROR_NO_VALID_CC, label, is(IsNull.notNullValue())); + + preferencesShell.close(); + + // reset env + environmentVariables.set(ENV_PATH, origPath); + } } diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java index 3f8cb014..3971db06 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java +++ b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java @@ -1,15 +1,22 @@ package org.codechecker.eclipse.plugin.utils; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import org.codechecker.eclipse.plugin.codechecker.locator.ResolutionMethodTypes; +import org.eclipse.swt.custom.CLabel; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.eclipse.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory; import org.eclipse.swtbot.swt.finder.results.VoidResult; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotRadio; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.swtbot.swt.finder.widgets.SWTBotText; import org.eclipse.ui.PlatformUI; +import org.hamcrest.Matcher; /** * Helper functions for navigating the gui. @@ -39,16 +46,17 @@ public final class GuiUtils { public static final String ADD_NATURE_MENU = "Add CodeChecker Nature"; public static final String COMP_COMMANDS = "compilation_commands.json.javarunner"; public static final String BIN = "bin"; - public static final String CC_DIR_WIDGET = "CodeChecker package root directory"; + public static final String CC_DIR_WIDGET = "CodeChecker binary:"; public static final String CODECHECKER = "CodeChecker"; public static final String ENVIR_LOGGER_BIN = "CC_LOGGER_BIN"; public static final String ENVIR_LOGGER_FILE = "CC_LOGGER_FILE"; public static final String LDOGGER = "ldlogger"; - public static final String PY_DIR_WIDGET = "Python virtualenv root directory (optional)"; + public static final String PY_DIR_WIDGET = "Virtual env:"; public static final String GLOBAL_RADIO = "Use global configuration"; public static final String PROJECT_RADIO = "Use project configuration"; public static final int SHORT_WAIT_TIME = 500; // in milliseconds + public static final int LONG_TIME_OUT = 10000; /** * Not called. */ @@ -97,23 +105,57 @@ public static void applyCloseProperties(SWTBotShell propertiesShell, SWTWorkbenc closeShell(propertiesShell, true, bot); } + /** + * Convenience method with pre built package. + * + * @param ccDir + * Path to the CodeChecker Root directory. + * @param bot + * The bot to be guided. + */ + public static void setCCBinDir(Path ccDir, SWTWorkbenchBot bot) { + setCCBinDir(ResolutionMethodTypes.PRE, ccDir, bot, true); + } + /** * You MUST navigate to the correct preferences page, or the method fails and * possibly throws widget not found exception. Sets The CodeChecker Directory on * the preferences pages. * + * @param method + * The associated radio button to the {@link ResolutionMethodTypes} + * will be clicked on the preferences/properties page. * @param ccDir * Path to the CodeChecker Root directory. * @param bot * The bot to be guided. + * @param root + * TODO */ - public static void setCCBinDir(Path ccDir, SWTWorkbenchBot bot) { - SWTBotText text = bot.textWithLabel(GuiUtils.CC_DIR_WIDGET); - text.setText(ccDir.toString()); - text.setFocus(); - bot.textWithLabel(GuiUtils.PY_DIR_WIDGET).setFocus(); - - bot.sleep(SHORT_WAIT_TIME); + public static void setCCBinDir(ResolutionMethodTypes method, Path ccDir, SWTWorkbenchBot bot, boolean root) { + SWTBotRadio radio = null; + switch (method) { + case PATH: + radio = bot.radio("Search in PATH"); + break; + case PRE: + radio = bot.radio("Pre built package"); + break; + case PY: + radio = bot.radio("Custom built package"); + break; + default: + break; + } + radio.click(); + if (method != ResolutionMethodTypes.PATH || ccDir != null) { + SWTBotText text = bot.textWithLabel(GuiUtils.CC_DIR_WIDGET); + if (root) + ccDir = Paths.get(ccDir.toAbsolutePath().toString(), BIN, CODECHECKER); + text.setText(ccDir.toString()); + bot.sleep(SHORT_WAIT_TIME); + // Handle Python specified... + } } /** @@ -134,7 +176,7 @@ public static void deleteProject(String projectName, boolean deleteFromDisk, SWT if (deleteFromDisk) bot.checkBox("Delete project contents on disk (cannot be undone)").select(); bot.button("OK").click(); - bot.waitUntil(Conditions.shellCloses(shell)); + bot.waitUntil(Conditions.shellCloses(shell), LONG_TIME_OUT); } /** @@ -194,7 +236,7 @@ public void run() { * @param tab * The desired preferences tab. * @param bot - * the workbench bot to be used. + * The workbench bot to be used. * @return The newly opened shell. */ public static SWTBotShell getPreferencesTab(String tab, SWTWorkbenchBot bot) { @@ -204,4 +246,19 @@ public static SWTBotShell getPreferencesTab(String tab, SWTWorkbenchBot bot) { bot.tree().getTreeItem(tab).select(); return shell; } + + /** + * Designed to find the message header CLabel in an SWT From. + * + * @param prefix + * This prefix will be searched. + * @param bot + * The workbench bot to be used. + * @return returns the CLabel instance. + */ + public static CLabel findCLabel(String prefix, SWTWorkbenchBot bot) { + Matcher matcher = WidgetMatcherFactory.widgetOfType(CLabel.class); + List widgets = bot.widgets(matcher); + return widgets.stream().filter(item -> item.getText().startsWith(prefix)).findFirst().get(); + } } diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/META-INF/MANIFEST.MF b/tests/org.codechecker.eclipse.rcp.unit.tests/META-INF/MANIFEST.MF index 66cae430..2a4e45d1 100644 --- a/tests/org.codechecker.eclipse.rcp.unit.tests/META-INF/MANIFEST.MF +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/META-INF/MANIFEST.MF @@ -11,6 +11,8 @@ Require-Bundle: org.junit, org.hamcrest;bundle-version="1.1.0", org.mockito;bundle-version="1.9.5", org.objenesis;bundle-version="1.0.0", - org.codechecker.eclipse.rcp.shared;bundle-version="1.0.0" + org.codechecker.eclipse.rcp.shared;bundle-version="1.0.0", + com.google.guava, + com.github.stefanbirkner.system-rules;bundle-version="1.19.0" Bundle-ClassPath: ., resources/ diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java new file mode 100644 index 00000000..7b0d0bad --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/CodeCheckerTest.java @@ -0,0 +1,126 @@ +package org.codechecker.eclipse.plugin.codechecker; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.codechecker.eclipse.plugin.codechecker.locator.InvalidCodeCheckerException; +import org.codechecker.eclipse.plugin.config.CcConfigurationBase; +import org.codechecker.eclipse.plugin.config.Config.ConfigTypes; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelper; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelperFactory; +import org.codechecker.eclipse.rcp.shared.utils.Utils; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import com.google.common.base.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests to test functionality of {@link CodeChecker}. + */ +public class CodeCheckerTest { + private static final int RUN_COUNT = 123; + + private static final String DUMMY = "/home"; + private static final String ERROR_COULDNT_CREATE_CC = "Couldn't create CodeChecker instance!"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private Path codeCheckerPath = Utils.prepareCodeChecker(); + private Path notACodeCheckerPath = Paths.get(DUMMY); + private ShellExecutorHelper she; + + /** + * Initialitze a CodeChecker test package and also a dummy path, and a + * {@link ShellExecutorHelper} with a default system environment. + */ + @Before + public void init() { + codeCheckerPath = Utils.prepareCodeChecker().resolve(Paths.get("bin", "CodeChecker")); + notACodeCheckerPath = Paths.get(DUMMY); + she = new ShellExecutorHelperFactory().createShellExecutorHelper(System.getenv()); + } + + /** + * Test that an exception is thrown when a CodeChecker is tred to be constructed + * with an invalid(no codechecker at that location). + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testInvalidPath() throws InvalidCodeCheckerException { + thrown.expect(InvalidCodeCheckerException.class); + new CodeChecker(notACodeCheckerPath, she); + } + + /** + * Test that the version string is returned. + */ + @Test + public void testVersionReturned() { + ICodeChecker codeChecker = null; + try { + codeChecker = new CodeChecker(codeCheckerPath, she); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + + try { + String version = codeChecker.getVersion(); + assertThat("Missing Version String", version.startsWith("CodeChecker analyzer version:")); + } catch (InvalidCodeCheckerException e) { + fail("An exception was thrown after a successful initialization!"); + } + } + + /** + * Test that the correct path is returned. + */ + @Test + public void testPathIsCorrect() { + ICodeChecker codeChecker = null; + try { + codeChecker = new CodeChecker(codeCheckerPath, she); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + assertThat("Path to CodeChecker wasn't the same", codeCheckerPath.compareTo(codeChecker.getLocation()) == 0); + } + + /** + * Simple test for running an analysis. + */ + @Test + public void analyzeTest() { + ICodeChecker codeChecker = null; + ShellExecutorHelper mockShe = Mockito.spy(new ShellExecutorHelper(System.getenv())); + try { + codeChecker = new CodeChecker(codeCheckerPath, mockShe); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + CcConfigurationBase configMock = mock(CcConfigurationBase.class); + final String cores = "3 "; + final String checkers = "-e Checker 1, -e Checker2 "; + final String analyzeMockString = "Running analysis! with" + cores + checkers; + when(configMock.get(ConfigTypes.ANAL_THREADS)).thenReturn(cores); + when(configMock.get(ConfigTypes.CHECKER_LIST)).thenReturn(checkers); + NullProgressMonitor mon = new NullProgressMonitor(); + when(mockShe.progressableWaitReturnOutput(anyString(), Mockito.anyBoolean(), Mockito.eq(mon), + Mockito.eq(RUN_COUNT))) + .thenReturn(Optional.of(analyzeMockString)); + String analyzeResult = codeChecker.analyze(Paths.get(DUMMY), true, mon, RUN_COUNT, configMock); + assertThat("Analyze result isn't the same as specified", analyzeResult.equals(analyzeMockString)); + } +} diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java new file mode 100644 index 00000000..cdabc234 --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java @@ -0,0 +1,112 @@ +package org.codechecker.eclipse.plugin.codechecker.locator; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.codechecker.eclipse.plugin.codechecker.CodeCheckerFactory; +import org.codechecker.eclipse.plugin.codechecker.ICodeCheckerFactory; +import org.codechecker.eclipse.plugin.runtime.IShellExecutorHelperFactory; +import org.codechecker.eclipse.plugin.runtime.ShellExecutorHelperFactory; +import org.codechecker.eclipse.rcp.shared.utils.Utils; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.fail; + +/** + * {@link CodeCheckerLocatorService} tests. + */ +public class CodeCheckerLocatorTest { + + private static final String ENV_PATH = "PATH"; + private static final String DUMMY = "/home"; + private static final String ERROR_COULDNT_CREATE_CC = "Couldn't create CodeChecker instance!"; + private static final Path CC_PATH = Utils.prepareCodeChecker(); + private static final Path PATH_CC_PATH = Utils.prepareCodeChecker(); + private static final Path NOT_CC_PATH = Paths.get(DUMMY); + // TODO implement virtual environment emulation + // private static final Path venvPath = Paths.get(DUMMY); + private static final ICodeCheckerFactory CC_FACTORY = new CodeCheckerFactory(); + private static final IShellExecutorHelperFactory SHEF = new ShellExecutorHelperFactory(); + + private static CodeCheckerLocatorFactory cclf; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + + /** + * This factory can be used for the entire test. + */ + @BeforeClass + public static void setUpBeforeClass() { + cclf = new CodeCheckerLocatorFactory(); + } + + /** + * Test {@link EnvCodeCheckerLocatorService}. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPath() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PATH); + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(EnvCodeCheckerLocatorService.ERROR); + + serv.findCodeChecker(null, null, CC_FACTORY, SHEF); + // prepare PATH envval + String origPath = System.getenv(ENV_PATH); + String newPath = origPath.concat(":" + PATH_CC_PATH.toAbsolutePath().toString() + "/bin/"); + + // Set the prepared PATH + environmentVariables.set(ENV_PATH, newPath); + + serv = cclf.create(ResolutionMethodTypes.PATH); + try { + serv.findCodeChecker(null, null, CC_FACTORY, SHEF); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + // reset env + environmentVariables.set(ENV_PATH, origPath); + } + + /** + * Test {@link PreBuiltCodeCheckerLocatorService}. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPre() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PRE); + + thrown.expect(RuntimeException.class); + thrown.expectMessage(PreBuiltCodeCheckerLocatorService.INVALID); + // Test null + serv.findCodeChecker(null, null, CC_FACTORY, SHEF); + + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(PreBuiltCodeCheckerLocatorService.ERROR); + // Test garbage + serv.findCodeChecker(Paths.get("gdfsg"), null, CC_FACTORY, SHEF); + + // Test not valid + serv.findCodeChecker(NOT_CC_PATH, null, CC_FACTORY, SHEF); + + // Test valid + serv = cclf.create(ResolutionMethodTypes.PATH); + try { + serv.findCodeChecker(CC_PATH, null, CC_FACTORY, SHEF); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + } +} diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java new file mode 100644 index 00000000..7483a6d9 --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/package-info.java @@ -0,0 +1,4 @@ +/** + * Unit tests. + */ +package org.codechecker.eclipse.plugin.codechecker.locator; \ No newline at end of file diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/package-info.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/package-info.java new file mode 100644 index 00000000..2c9cec3d --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/package-info.java @@ -0,0 +1,4 @@ +/** + * Unit tests. + */ +package org.codechecker.eclipse.plugin.codechecker; \ No newline at end of file From cfdee34f06638a5d4a5b920a5465271653c471a1 Mon Sep 17 00:00:00 2001 From: Vodorok Date: Wed, 31 Jul 2019 13:43:17 +0200 Subject: [PATCH 3/4] Add python virtual environment emulation CodeChecker dummy was modified to be able to behave like a custom built package needing a python virtual environment to be sourced. Helper methods are also added to be able to create a package like this for the tests to be used. --- .../resources/CodeChecker/bin/CodeChecker | 10 +- .../resources/CodeChecker/venv/bin/activate | 3 + .../eclipse/rcp/shared/utils/Utils.java | 102 ++++++++++++++---- 3 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/venv/bin/activate diff --git a/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/bin/CodeChecker b/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/bin/CodeChecker index 1527abc7..114c1e02 100755 --- a/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/bin/CodeChecker +++ b/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/bin/CodeChecker @@ -3,13 +3,21 @@ CodeChecker Stub used to emulate some CodeChecker commands for the tests. """ -import sys import argparse +import os +import sys + +#CUSTOM_BUILT=True + +def customHandler(): + os.environ['CC_VIRTUAL_ENV'] """ Handler function for version information. """ def version(args): + if "CUSTOM_BUILT" in globals(): + customHandler() print("""CodeChecker analyzer version: --------------------------------------------------------------- Kind | Version diff --git a/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/venv/bin/activate b/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/venv/bin/activate new file mode 100644 index 00000000..b633248f --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.shared/resources/CodeChecker/venv/bin/activate @@ -0,0 +1,3 @@ +CC_VIRTUAL_ENV=1 +export CC_VIRTUAL_ENV + diff --git a/tests/org.codechecker.eclipse.rcp.shared/src/org/codechecker/eclipse/rcp/shared/utils/Utils.java b/tests/org.codechecker.eclipse.rcp.shared/src/org/codechecker/eclipse/rcp/shared/utils/Utils.java index 90b67cfa..2610dffb 100644 --- a/tests/org.codechecker.eclipse.rcp.shared/src/org/codechecker/eclipse/rcp/shared/utils/Utils.java +++ b/tests/org.codechecker.eclipse.rcp.shared/src/org/codechecker/eclipse/rcp/shared/utils/Utils.java @@ -8,6 +8,8 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.PosixFilePermissions; +import java.util.List; +import java.util.stream.Collectors; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; @@ -72,47 +74,111 @@ public static Path copyFolder(Path src, Path dest) { } /** - * Convenience method for quickly get a runnable CodeChecker. - * Has the same effect to loadCodeChecker("CodeChecker"). - * Copies into the default directory layout, and sets runnable permission to Codechecker. - * The path to the runnable CodeChecker will be tmp//CodeChecker/bin/CodeChecker - * @return The path to To the CodeChecker root directory. - * Will point to tmp//CodeChecker . + * Use this if you want to create a CodeChecker without thinking. This should be + * sufficient for most applications. Convenience method for quickly get a + * runnable CodeChecker. Has the same effect to + * prepareCodeChecker("CodeChecker"). Copies into the default directory layout, + * and sets runnable permission to Codechecker. The path to the runnable + * CodeChecker will be tmp//CodeChecker/bin/CodeChecker + * + * @return The path to To the CodeChecker root directory. Will point to + * tmp//CodeChecker . */ public static Path prepareCodeChecker() { - return prepareCodeChecker(CODECHECKER); + return prepareCodeChecker(CODECHECKER, false); } /** - * Copies into the specified directory, and sets runnable permission to Codechecker. - * The path to the runnable CodeChecker will be tmp///bin/CodeChecker - * @param into This will be the name of the CodeChecker root folder. - * @return The path to To the CodeChecker root directory. - * Will point to tmp// . + * This will create a runnable into the default folder. Convenience method for + * quickly get a runnable CodeChecker. Has the same effect to + * prepareCodeChecker("CodeChecker"). Copies into the default directory layout, + * and sets runnable permission to Codechecker. The path to the runnable + * CodeChecker will be tmp//CodeChecker/bin/CodeChecker + * + * @param customBuilt + * Set this flag to indicate that the CodeChecker being prepared + * should behave like a Custom built instance requiring a virtual + * environment. + * @return The path to To the CodeChecker root directory. Will point to + * tmp//CodeChecker . + */ + public static Path prepareCodeChecker(boolean customBuilt) { + return prepareCodeChecker(CODECHECKER, customBuilt); + } + + /** + * This will create a runnable prebuilt mimicking CodeChecker instance into the + * "into" folder. Copies into the specified directory, and sets runnable + * permission to Codechecker. The path to the runnable CodeChecker will be + * tmp///bin/CodeChecker + * + * @param into + * This will be the name of the CodeChecker root folder. + * @return The path to To the CodeChecker root directory. Will point to + * tmp// . */ public static Path prepareCodeChecker(String into) { - if (into.isEmpty() || into == null) throw new IllegalArgumentException(); - + return prepareCodeChecker(into, false); + } + + /** + * Copies into the specified directory, and sets runnable permission to + * Codechecker. The path to the runnable CodeChecker will be + * tmp///bin/CodeChecker + * + * @param into + * This will be the name of the CodeChecker root folder. + * @param customBuilt + * Set this flag to indicate that the CodeChecker being prepared + * should behave like a Custom built instance requiring a virtual + * environment. + * @return The path to To the CodeChecker root directory. Will point to + * tmp// . + */ + public static Path prepareCodeChecker(String into, boolean customBuilt) { + if (into.isEmpty() || into == null) + throw new IllegalArgumentException(); + Path testDir = null; Path ccRoot = null; try { testDir = Files.createTempDirectory("CCTest"); testDir.toFile().deleteOnExit(); testDir = Files.createDirectory(Paths.get(testDir.toString(), into)); - ccRoot = Utils.loadFileFromBundle("org.codechecker.eclipse.rcp.shared", - Utils.RES + CODECHECKER); + ccRoot = Utils.loadFileFromBundle("org.codechecker.eclipse.rcp.shared", Utils.RES + CODECHECKER); } catch (IOException | URISyntaxException e1) { e1.printStackTrace(System.out); } - // Get the CodeChecker stub from the test resources, and copy it to a temporary folder. + // Get the CodeChecker stub from the test resources, and copy it to a temporary + // folder. Path ccDir = Utils.copyFolder(ccRoot, testDir); - Path ccBinDir = Paths.get( testDir.toAbsolutePath().toString(), CODECHECKER, BIN, CODECHECKER); + Path ccBinDir = Paths.get(testDir.toAbsolutePath().toString(), CODECHECKER, BIN, CODECHECKER); try { // CodeChecker must be runnable. Files.setPosixFilePermissions(ccBinDir, PosixFilePermissions.fromString("rwxrwxrwx")); } catch (IOException e) { e.printStackTrace(); } + if (customBuilt) + // tamper CodeChecker to act like a custom built. + setCustomBuilt(ccDir); return ccDir; } + + /** + * Changes the dummy CodeChecker behavior to Custom built like. + * + * @param ccDir + * The path to the CodeChecker root. + */ + private static void setCustomBuilt(Path ccDir) { + Path bin = ccDir.resolve(Paths.get(BIN, CODECHECKER)); + try { + List allLines = Files.readAllLines(bin).stream() + .map(e -> e.replaceFirst("#CUSTOM_BUILT=True", "CUSTOM_BUILT=True")).collect(Collectors.toList()); + Files.write(bin, allLines); + } catch (IOException e) { + e.printStackTrace(); + } + } } From 858326d9b04ceb6b61538d1bb5ce697b9133ac29 Mon Sep 17 00:00:00 2001 From: Vodorok Date: Wed, 31 Jul 2019 14:00:28 +0200 Subject: [PATCH 4/4] Test virtual env CodeChecker packages Test the indicator workings of virtual environment dependent CodeChecker. Test for CustomBuiltCodeCheckerLocatorService. --- .../CustomBuiltCodeCheckerLocatorService.java | 3 +- .../codechecker/eclipse/plugin/AllTests.java | 5 +- .../eclipse/plugin/IndicatorTest.java | 20 +++ .../eclipse/plugin/utils/GuiUtils.java | 39 ++++- .../locator/CodeCheckerLocatorTest.java | 136 +++++++++++++++++- 5 files changed, 193 insertions(+), 10 deletions(-) diff --git a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java index 655eada6..75ada36a 100644 --- a/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java @@ -23,10 +23,9 @@ public class CustomBuiltCodeCheckerLocatorService extends CodeCheckerLocatorServ @Override public ICodeChecker findCodeChecker(Path pathToBin, Path pathToVenv, ICodeCheckerFactory ccfactory, IShellExecutorHelperFactory sheFactory) throws InvalidCodeCheckerException { - ShellExecutorHelper she = sheFactory.createShellExecutorHelper(System.getenv()); Optional output = she - .quickReturnOutput("source " + pathToVenv.toAbsolutePath().toString() + "/bin/activate ; env"); + .quickReturnOutput(". " + pathToVenv.toAbsolutePath().toString() + "/bin/activate ; env"); if (!output.isPresent()) throw new IllegalArgumentException(); try { diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/AllTests.java b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/AllTests.java index 157c009a..ebe17589 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/AllTests.java +++ b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/AllTests.java @@ -11,9 +11,8 @@ * Test Suite for running the gui tests. Add your class to the Suite class list. */ @RunWith(Suite.class) -@SuiteClasses({ PluginTest.class, - IndicatorTest.class, - ConfigurationTest.class}) +@SuiteClasses({ PluginTest.class, IndicatorTest.class, ConfigurationTest.class, }) + public class AllTests { /** diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java index 31413824..88e890e2 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java +++ b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/IndicatorTest.java @@ -151,4 +151,24 @@ public void testCodeCheckerFoundInPath() { // reset env environmentVariables.set(ENV_PATH, origPath); } + + /** + * Test that with Custom built CodeChecker configured, a confirmation message is + * displayed. + */ + @Test + public void testCustomCodeCheckerFound() { + Path ccDir = Utils.prepareCodeChecker(true); + GuiUtils.setCCBinDir(ResolutionMethodTypes.PY, ccDir, bot, true); + SWTBotCLabel label = null; + + try { + label = new SWTBotCLabel(GuiUtils.findCLabel(FORM_MESSAGE_CC_FOUND, bot)); + } catch (WidgetNotFoundException e) { + System.out.println(e.getMessage()); + } + assertThat(ERROR_NO_VALID_CC, label, is(IsNull.notNullValue())); + + preferencesShell.close(); + } } diff --git a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java index 3971db06..30ff645e 100644 --- a/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java +++ b/tests/org.codechecker.eclipse.rcp.it.tests/src/org/codechecker/eclipse/plugin/utils/GuiUtils.java @@ -5,6 +5,7 @@ import java.util.List; import org.codechecker.eclipse.plugin.codechecker.locator.ResolutionMethodTypes; +import org.codechecker.eclipse.plugin.config.CommonGui; import org.eclipse.swt.custom.CLabel; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.eclipse.finder.waits.Conditions; @@ -46,7 +47,9 @@ public final class GuiUtils { public static final String ADD_NATURE_MENU = "Add CodeChecker Nature"; public static final String COMP_COMMANDS = "compilation_commands.json.javarunner"; public static final String BIN = "bin"; - public static final String CC_DIR_WIDGET = "CodeChecker binary:"; + public static final String VENV = "venv"; + public static final String CC_DIR_WIDGET = CommonGui.CC_BIN_LABEL; + public static final String CC_VENV_WIDGET = CommonGui.VENV_LABEL; public static final String CODECHECKER = "CodeChecker"; public static final String ENVIR_LOGGER_BIN = "CC_LOGGER_BIN"; public static final String ENVIR_LOGGER_FILE = "CC_LOGGER_FILE"; @@ -130,9 +133,31 @@ public static void setCCBinDir(Path ccDir, SWTWorkbenchBot bot) { * @param bot * The bot to be guided. * @param root - * TODO + * If the path passed in ccDir points to the root of the Package. */ public static void setCCBinDir(ResolutionMethodTypes method, Path ccDir, SWTWorkbenchBot bot, boolean root) { + setCCBinDir(method, ccDir, null, bot, root); + } + + /** + * You MUST navigate to the correct preferences page, or the method fails and + * possibly throws widget not found exception. Sets The CodeChecker Directory on + * the preferences pages. + * + * @param method + * The associated radio button to the {@link ResolutionMethodTypes} + * will be clicked on the preferences/properties page. + * @param ccDir + * Path to the CodeChecker Root directory. + * @param venvDir + * Path to the virtual envioronment. + * @param bot + * The bot to be guided. + * @param root + * If the path passed in ccDir points to the root of the Package. + */ + public static void setCCBinDir(ResolutionMethodTypes method, Path ccDir, Path venvDir, SWTWorkbenchBot bot, + boolean root) { SWTBotRadio radio = null; switch (method) { case PATH: @@ -153,8 +178,14 @@ public static void setCCBinDir(ResolutionMethodTypes method, Path ccDir, SWTWork if (root) ccDir = Paths.get(ccDir.toAbsolutePath().toString(), BIN, CODECHECKER); text.setText(ccDir.toString()); - bot.sleep(SHORT_WAIT_TIME); - // Handle Python specified... + if (method == ResolutionMethodTypes.PY /* && venvDir != null */) { + SWTBotText venvText = bot.textWithLabel(GuiUtils.CC_VENV_WIDGET); + if (root) + venvText.setText(ccDir.getParent().getParent().toAbsolutePath().resolve(Paths.get(VENV)) + .toString().toString()); + else + venvText.setText(ccDir.toAbsolutePath().resolve(Paths.get(VENV)).toString()); + } } } diff --git a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java index cdabc234..038f7872 100644 --- a/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java @@ -23,10 +23,15 @@ public class CodeCheckerLocatorTest { private static final String ENV_PATH = "PATH"; private static final String DUMMY = "/home"; + private static final String GARBAGE = "garbage"; private static final String ERROR_COULDNT_CREATE_CC = "Couldn't create CodeChecker instance!"; private static final Path CC_PATH = Utils.prepareCodeChecker(); private static final Path PATH_CC_PATH = Utils.prepareCodeChecker(); + private static final Path CUSTOM_CC_PATH = Utils.prepareCodeChecker(true).resolve(Paths.get("bin", "CodeChecker")); + private static final Path VENV_PATH = CUSTOM_CC_PATH.getParent().getParent().toAbsolutePath() + .resolve(Paths.get("venv")); private static final Path NOT_CC_PATH = Paths.get(DUMMY); + private static final Path NOT_VENV_PATH = Paths.get(DUMMY); // TODO implement virtual environment emulation // private static final Path venvPath = Paths.get(DUMMY); private static final ICodeCheckerFactory CC_FACTORY = new CodeCheckerFactory(); @@ -96,7 +101,7 @@ public void testPre() throws InvalidCodeCheckerException { thrown.expect(InvalidCodeCheckerException.class); thrown.expectMessage(PreBuiltCodeCheckerLocatorService.ERROR); // Test garbage - serv.findCodeChecker(Paths.get("gdfsg"), null, CC_FACTORY, SHEF); + serv.findCodeChecker(Paths.get(GARBAGE), null, CC_FACTORY, SHEF); // Test not valid serv.findCodeChecker(NOT_CC_PATH, null, CC_FACTORY, SHEF); @@ -109,4 +114,133 @@ public void testPre() throws InvalidCodeCheckerException { fail(ERROR_COULDNT_CREATE_CC); } } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with null - null + * Path paramaters as input throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyNullNull() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(NullPointerException.class); + // Test null + serv.findCodeChecker(null, null, CC_FACTORY, SHEF); + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with null venv Path + * paramaters as input throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyPreCCNull() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(NullPointerException.class); + // Test null + serv.findCodeChecker(CC_PATH, null, CC_FACTORY, SHEF); + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with null venv Path + * paramaters as input throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyCustCCNull() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(NullPointerException.class); + // Test valid Custom - null + serv.findCodeChecker(CUSTOM_CC_PATH, null, CC_FACTORY, SHEF); + + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with Paths pointing + * to some random location throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyRandRand() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(CustomBuiltCodeCheckerLocatorService.ERROR); + + // Test not valid + serv.findCodeChecker(NOT_CC_PATH, NOT_VENV_PATH, CC_FACTORY, SHEF); + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with Paths pointing + * to some random location throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyPreCCRand() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(CustomBuiltCodeCheckerLocatorService.ERROR); + // Test valid Pre - not Venv + serv.findCodeChecker(CC_PATH, NOT_VENV_PATH, CC_FACTORY, SHEF); + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with Paths pointing + * to some random location throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyCustCCGarb() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(CustomBuiltCodeCheckerLocatorService.ERROR); + // Test valid Custom - garbage + serv.findCodeChecker(CUSTOM_CC_PATH, Paths.get(GARBAGE), CC_FACTORY, SHEF); + } + + /** + * Test {@link CustomBuiltCodeCheckerLocatorService} called with Paths pointing + * to some random location throws nullpointer exception. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPyCustCCRand() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + thrown.expect(InvalidCodeCheckerException.class); + thrown.expectMessage(CustomBuiltCodeCheckerLocatorService.ERROR); + // Test valid Custom - not Venv + serv.findCodeChecker(CUSTOM_CC_PATH, NOT_VENV_PATH, CC_FACTORY, SHEF); + } + + /** + * Test {@link PreBuiltCodeCheckerLocatorService}. + * + * @throws InvalidCodeCheckerException + * For testing purposes. + */ + @Test + public void testPy() throws InvalidCodeCheckerException { + CodeCheckerLocatorService serv = cclf.create(ResolutionMethodTypes.PY); + // Test valid Custom - Venv + try { + serv.findCodeChecker(CUSTOM_CC_PATH, VENV_PATH, CC_FACTORY, SHEF); + } catch (InvalidCodeCheckerException e) { + fail(ERROR_COULDNT_CREATE_CC); + } + } }