/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.project.build.validation; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.assertj.core.api.Condition; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.runtime.CoreException; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.rf.ide.core.executor.SuiteExecutor; import org.rf.ide.core.project.RobotProjectConfig.ReferencedLibrary; import org.rf.ide.core.project.RobotProjectConfig.SearchPath; import org.rf.ide.core.testdata.model.RobotVersion; import org.rf.ide.core.testdata.model.table.setting.VariablesImport; import org.rf.ide.core.validation.ProblemPosition; import org.robotframework.ide.eclipse.main.plugin.model.RobotModel; import org.robotframework.ide.eclipse.main.plugin.model.RobotProject; import org.robotframework.ide.eclipse.main.plugin.model.RobotSettingsSection; import org.robotframework.ide.eclipse.main.plugin.model.RobotSuiteFile; import org.robotframework.ide.eclipse.main.plugin.project.build.causes.GeneralSettingsProblem; import org.robotframework.ide.eclipse.main.plugin.project.build.validation.MockReporter.Problem; import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecification; import org.robotframework.red.junit.ProjectProvider; import org.robotframework.red.junit.ResourceCreator; import com.google.common.collect.Range; public class GeneralSettingsVariablesImportValidatorTest { public static ProjectProvider projectProvider = new ProjectProvider( GeneralSettingsVariablesImportValidatorTest.class); public static TemporaryFolder tempFolder = new TemporaryFolder(); @ClassRule public static TestRule rulesChain = RuleChain.outerRule(projectProvider).around(tempFolder); @Rule public ResourceCreator resourceCreator = new ResourceCreator(); private RobotModel model; private MockReporter reporter; @BeforeClass public static void beforeSuite() throws Exception { final File root = tempFolder.getRoot(); getFile(root, "external.py").createNewFile(); getFile(root, "external_dir").mkdir(); getFile(root, "external_dir", "external_nested.py").createNewFile(); getFile(root, "external_dir", "external_nested.txt").createNewFile(); projectProvider.configure(); } @Before public void beforeTest() { model = new RobotModel(); reporter = new MockReporter(); } @Test public void markerIsReported_whenImportIsNotSpecified() { validateVariablesImport(""); assertThat(reporter.getReportedProblems()).containsExactly(new Problem( GeneralSettingsProblem.MISSING_VARIABLES_NAME, new ProblemPosition(2, Range.closed(17, 26)))); } @Test public void markerIsReported_whenImportingUnknownThing() { validateVariablesImport("something"); assertThat(reporter.getReportedProblems()).containsExactly(new Problem( GeneralSettingsProblem.NON_EXISTING_VARIABLES_IMPORT, new ProblemPosition(2, Range.closed(28, 37)))); } @Test public void markerIsReported_whenImportContainsUnknownVariables() { validateVariablesImport("${unknown}/file.py"); assertThat(reporter.getReportedProblems()).containsExactly(new Problem( GeneralSettingsProblem.IMPORT_PATH_PARAMETERIZED, new ProblemPosition(2, Range.closed(28, 46)))); } @Test public void markerIsReported_whenUsingUnescapedWindowsPaths_1() { validateVariablesImport("d:\\folder\\res.py"); assertThat(reporter.getReportedProblems()).containsOnly(new Problem( GeneralSettingsProblem.IMPORT_PATH_USES_SINGLE_WINDOWS_SEPARATORS, new ProblemPosition(2, Range.closed(28, 44)))); } @Test public void markerIsReported_whenUsingUnescapedWindowsPaths_2() { validateVariablesImport("..\\..\\res.py"); assertThat(reporter.getReportedProblems()).containsOnly(new Problem( GeneralSettingsProblem.IMPORT_PATH_USES_SINGLE_WINDOWS_SEPARATORS, new ProblemPosition(2, Range.closed(28, 40)))); } @Test public void markerIsReported_whenUsingUnescapedWindowsPaths_3() { validateVariablesImport("..\\../res.py"); assertThat(reporter.getReportedProblems()).containsOnly(new Problem( GeneralSettingsProblem.IMPORT_PATH_USES_SINGLE_WINDOWS_SEPARATORS, new ProblemPosition(2, Range.closed(28, 40)))); } @Test public void markerIsReported_whenUsingAbsolutePathImport() throws Exception { final File tmpFile = tempFolder.newFile("file.py"); final String absPath = tmpFile.getAbsolutePath().replaceAll("\\\\", "/"); validateVariablesImport(absPath); assertThat(reporter.getReportedProblems()).contains(new Problem(GeneralSettingsProblem.IMPORT_PATH_ABSOLUTE, new ProblemPosition(2, Range.closed(28, 28 + absPath.length())))); } @Test public void markerIsReported_whenFileIsImportedRelativelyViaSysPathInsteadOfLocally() throws Exception { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "external_nested.py"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(newArrayList(tmpFile.getParentFile())); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .contains(new Problem(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH, new ProblemPosition(2, Range.closed(28, 46)))); } @Test public void markerIsReported_whenFileIsImportedRelativelyViaRedXmlPythonPathInsteadOfLocally() throws Exception { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "external_nested.py"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(new ArrayList<File>()); final List<SearchPath> paths = newArrayList(SearchPath.create(tmpFile.getParent())); robotProject.getRobotProjectConfig().setPythonPath(paths); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .contains(new Problem(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH, new ProblemPosition(2, Range.closed(28, 46)))); robotProject.getRobotProjectConfig().setPythonPath(null); } @Test public void markerIsReported_whenFileIsImportedFromOutsideOfWorkspace_1() { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "external_nested.py"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(newArrayList(tmpFile.getParentFile())); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()).contains(new Problem( GeneralSettingsProblem.IMPORT_PATH_OUTSIDE_WORKSPACE, new ProblemPosition(2, Range.closed(28, 46)))); } @Test public void markerIsReported_whenFileIsImportedFromOutsideOfWorkspace_2() { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "external_nested.py"); final String absPath = tmpFile.getAbsolutePath().replaceAll("\\\\", "/"); validateVariablesImport(absPath); assertThat(reporter.getReportedProblems()) .contains(new Problem(GeneralSettingsProblem.IMPORT_PATH_OUTSIDE_WORKSPACE, new ProblemPosition(2, Range.closed(28, 28 + absPath.length())))); } @Test public void markerIsReported_whenExternalFileDoesNotExist() { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "non_existing.py"); final String absPath = tmpFile.getAbsolutePath().replaceAll("\\\\", "/"); validateVariablesImport(absPath); assertThat(reporter.getReportedProblems()).contains( new Problem(GeneralSettingsProblem.NON_EXISTING_VARIABLES_IMPORT, new ProblemPosition(2, Range.closed(28, 28 + absPath.length())))); } @Test public void markerIsReported_whenFileInWorkspaceDoesNotExist() { validateVariablesImport("non_existing.py"); assertThat(reporter.getReportedProblems()).contains(new Problem( GeneralSettingsProblem.NON_EXISTING_VARIABLES_IMPORT, new ProblemPosition(2, Range.closed(28, 43)))); } @Test public void markerIsReported_whenImportedVariablesLiesInDifferentDirectory() throws Exception { final IFolder dir = projectProvider.createDir("dir"); projectProvider.createFile("dir/res.py"); validateVariablesImport("res.py"); assertThat(reporter.getReportedProblems()).containsExactly(new Problem( GeneralSettingsProblem.NON_EXISTING_VARIABLES_IMPORT, new ProblemPosition(2, Range.closed(28, 34)))); dir.delete(true, null); } @Test public void noMajorProblemsAreReported_whenVariablesFileExistLocally_1() throws Exception { final IFile file = projectProvider.createFile("res.robot"); validateVariablesImport("res.robot"); assertThat(reporter.getReportedProblems()).isEmpty(); file.delete(true, null); } @Test public void noMajorProblemsAreReported_whenVariablesFileExistLocally_2() throws Exception { final IFolder dir = projectProvider.createDir("directory"); projectProvider.createFile("directory/res.robot"); validateVariablesImport("directory/res.robot"); assertThat(reporter.getReportedProblems()).isEmpty(); dir.delete(true, null); } @Test public void noMajorProblemsAreReported_whenWorkspaceImportIsNotAFile() throws Exception { final IFolder dir = projectProvider.createDir("directory"); validateVariablesImport("directory"); assertThat(reporter.getReportedProblems()).isEmpty(); dir.delete(true, null); } @Test public void noMajorProblemsAreReported_whenExternalImportIsNotAFile() { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir"); final String absPath = tmpFile.getAbsolutePath().replaceAll("\\\\", "/"); validateVariablesImport(absPath); assertThat(reporter.getReportedProblems()).are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_ABSOLUTE, GeneralSettingsProblem.IMPORT_PATH_OUTSIDE_WORKSPACE)); } @Test public void noMajorProblemsAreReported_whenVariablesFileExistLocallyButIsImportedUsingAbsolutePath() throws Exception { final IFile resFile = projectProvider.createFile("res.robot"); final String absPath = resFile.getLocation().toString(); validateVariablesImport(absPath); assertThat(reporter.getReportedProblems()).are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_ABSOLUTE)); resFile.delete(true, null); } @Test public void noMajorProblemsAreReported_whenVariablesFileExistLocallyAsALinkToExternalFile() throws Exception { final File tmpFile = getFile(tempFolder.getRoot(), "external_dir", "external_nested.py"); resourceCreator.createLink(tmpFile.toURI(), projectProvider.getFile("link.py")); validateVariablesImport(tmpFile.getAbsolutePath().replaceAll("\\\\", "/")); assertThat(reporter.getReportedProblems()).are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_ABSOLUTE)); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaSysPathFromWorksapce() throws Exception { final IFolder dir = projectProvider.createDir("dir"); projectProvider.createFile("dir/res.robot"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(newArrayList(dir.getLocation().toFile())); validateVariablesImport("res.robot"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH)); dir.delete(true, null); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaSysPathFromExternalLocation() { final File dir = getFile(tempFolder.getRoot(), "external_dir"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(newArrayList(dir)); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH, GeneralSettingsProblem.IMPORT_PATH_OUTSIDE_WORKSPACE)); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaSysPathFromExternalLocationWhichIsLinkedInWorkspace() throws Exception { final File dir = getFile(tempFolder.getRoot(), "external_dir"); resourceCreator.createLink(dir.toURI(), projectProvider.getProject().getFolder("linking_dir")); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(newArrayList(dir)); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH)); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaRedXmlPythonPathFromWorksapce() throws Exception { final IFolder dir = projectProvider.createDir("dir"); projectProvider.createFile("dir/res.robot"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(new ArrayList<File>()); final List<SearchPath> paths = newArrayList(SearchPath.create(dir.getLocation().toString())); robotProject.getRobotProjectConfig().setPythonPath(paths); validateVariablesImport("res.robot"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH)); dir.delete(true, null); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaRedXmlPythonPathFromExternalLocation() { final File dir = getFile(tempFolder.getRoot(), "external_dir"); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(new ArrayList<File>()); final List<SearchPath> paths = newArrayList(SearchPath.create(dir.getAbsolutePath())); robotProject.getRobotProjectConfig().setPythonPath(paths); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH, GeneralSettingsProblem.IMPORT_PATH_OUTSIDE_WORKSPACE)); } @Test public void noMajorProblemsAreReported_whenVariablesFileIsImportedViaRedXmlPythonPathFromExternalLocationWhichIsLinkedInWorkspace() throws Exception { final File dir = getFile(tempFolder.getRoot(), "external_dir"); resourceCreator.createLink(dir.toURI(), projectProvider.getProject().getFolder("linking_dir")); final RobotProject robotProject = model.createRobotProject(projectProvider.getProject()); robotProject.setModuleSearchPaths(new ArrayList<File>()); final List<SearchPath> paths = newArrayList(SearchPath.create(dir.getAbsolutePath())); robotProject.getRobotProjectConfig().setPythonPath(paths); validateVariablesImport("external_nested.py"); assertThat(reporter.getReportedProblems()) .are(onlyCausedBy(GeneralSettingsProblem.IMPORT_PATH_RELATIVE_VIA_MODULES_PATH)); } private Condition<Problem> onlyCausedBy(final GeneralSettingsProblem... causes) { final Set<GeneralSettingsProblem> causesSet = newHashSet(causes); return new Condition<MockReporter.Problem>() { @Override public boolean matches(final Problem problem) { return causesSet.contains(problem.getCause()); } }; } private void validateVariablesImport(final String toImport) { final RobotSuiteFile suiteFile = createVariablesImportingSuite(toImport); final VariablesImport varsImport = getImport(suiteFile); final FileValidationContext context = prepareContext(suiteFile); final GeneralSettingsVariablesImportValidator validator = new GeneralSettingsVariablesImportValidator(context, suiteFile, newArrayList(varsImport), reporter); try { validator.validate(null); } catch (final CoreException e) { throw new IllegalStateException("Unable to validate", e); } } private RobotSuiteFile createVariablesImportingSuite(final String toImport) { try { final IFile file = projectProvider.createFile("suite.robot", "*** Settings ***", "Variables " + toImport); final RobotSuiteFile suite = model.createSuiteFile(file); suite.dispose(); return suite; } catch (IOException | CoreException e) { throw new IllegalStateException("Cannot create file", e); } } private FileValidationContext prepareContext(final RobotSuiteFile suiteFile) { final Map<String, LibrarySpecification> specs = new HashMap<>(); final Map<ReferencedLibrary, LibrarySpecification> refLibs = new HashMap<>(); final ValidationContext context = new ValidationContext(model, RobotVersion.from("0.0"), SuiteExecutor.Python, specs, refLibs); return new FileValidationContext(context, suiteFile.getFile()); } private VariablesImport getImport(final RobotSuiteFile suiteFile) { return (VariablesImport) suiteFile.findSection(RobotSettingsSection.class).get() .getChildren().get(0).getLinkedElement(); } private static File getFile(final File root, final String... path) { if (path == null || path.length == 0) { return root; } else { return getFile(new File(root, path[0]), Arrays.copyOfRange(path, 1, path.length)); } } }