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..75ada36a --- /dev/null +++ b/bundles/org.codechecker.eclipse.plugin/src/org/codechecker/eclipse/plugin/codechecker/locator/CustomBuiltCodeCheckerLocatorService.java @@ -0,0 +1,52 @@ +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(". " + 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/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/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 d2918f5b..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 @@ -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,110 @@ 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); + } + + /** + * 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 3f8cb014..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 @@ -1,15 +1,23 @@ 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.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; 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 +47,19 @@ 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 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"; 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 +108,85 @@ 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 + * If the path passed in ccDir points to the root of the Package. */ - 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(); + public static void setCCBinDir(ResolutionMethodTypes method, Path ccDir, SWTWorkbenchBot bot, boolean root) { + setCCBinDir(method, ccDir, null, bot, root); + } - bot.sleep(SHORT_WAIT_TIME); + /** + * 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: + 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()); + 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()); + } + } } /** @@ -134,7 +207,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 +267,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 +277,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.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(); + } + } } 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..038f7872 --- /dev/null +++ b/tests/org.codechecker.eclipse.rcp.unit.tests/src/org/codechecker/eclipse/plugin/codechecker/locator/CodeCheckerLocatorTest.java @@ -0,0 +1,246 @@ +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 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(); + 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(GARBAGE), 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); + } + } + + /** + * 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); + } + } +} 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 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"))); - } -}