From 2f04f30063a31b5928634085ac38fabdfe340a2b Mon Sep 17 00:00:00 2001 From: Sergey Mashkov Date: Fri, 20 Nov 2015 15:43:31 +0300 Subject: [PATCH] KT-10114 Maven: plugin doesn't recognize sourceDirs configured in the goal configuration --- idea/src/META-INF/maven.xml | 8 + .../idea/configuration/KotlinMavenImporter.kt | 139 ++++ .../idea/maven/KotlinMavenImporterTest.kt | 391 +++++++++++ .../idea/maven/MavenImportingTestCase.java | 585 +++++++++++++++++ .../kotlin/idea/maven/MavenTestCase.java | 617 ++++++++++++++++++ .../kotlin/idea/maven/NullMavenConsole.java | 49 ++ 6 files changed, 1789 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenImporter.kt create mode 100644 idea/tests/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt create mode 100644 idea/tests/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java create mode 100644 idea/tests/org/jetbrains/kotlin/idea/maven/MavenTestCase.java create mode 100644 idea/tests/org/jetbrains/kotlin/idea/maven/NullMavenConsole.java diff --git a/idea/src/META-INF/maven.xml b/idea/src/META-INF/maven.xml index 6f76714ba14..c43b790fb22 100644 --- a/idea/src/META-INF/maven.xml +++ b/idea/src/META-INF/maven.xml @@ -3,4 +3,12 @@ + + + + + + org.jetbrains.kotlin.idea.configuration.KotlinImporterComponent + + diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenImporter.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenImporter.kt new file mode 100644 index 00000000000..67f957eaca6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenImporter.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.configuration + +import com.intellij.openapi.components.* +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider +import com.intellij.openapi.module.Module +import org.jdom.Element +import org.jetbrains.idea.maven.importing.MavenImporter +import org.jetbrains.idea.maven.importing.MavenRootModelAdapter +import org.jetbrains.idea.maven.model.MavenPlugin +import org.jetbrains.idea.maven.project.MavenProject +import org.jetbrains.idea.maven.project.MavenProjectChanges +import org.jetbrains.idea.maven.project.MavenProjectsProcessorTask +import org.jetbrains.idea.maven.project.MavenProjectsTree +import org.jetbrains.jps.model.java.JavaSourceRootType +import org.jetbrains.jps.model.module.JpsModuleSourceRootType +import java.io.File +import java.util.* + +private val KotlinPluginGroupId = "org.jetbrains.kotlin" +private val KotlinPluginArtifactId = "kotlin-maven-plugin" +private val KotlinPluginSourceDirsConfig = "sourceDirs" + +class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtifactId) { + override fun preProcess(module: Module, mavenProject: MavenProject, changes: MavenProjectChanges, modifiableModelsProvider: IdeModifiableModelsProvider) { + } + + override fun process(modifiableModelsProvider: IdeModifiableModelsProvider, + module: Module, + rootModel: MavenRootModelAdapter, + mavenModel: MavenProjectsTree, + mavenProject: MavenProject, + changes: MavenProjectChanges, + mavenProjectToModuleName: MutableMap, + postTasks: MutableList) { + + if (changes.plugins) { + contributeSourceDirectories(mavenProject, module, rootModel) + } + } + + // TODO in theory it should work like this but it doesn't as it couldn't unmark source roots that are not roots anymore. + // I believe this is something should be done by the underlying maven importer implementation or somewhere else in the IDEA + // For now there is a contributeSourceDirectories implementation that deals with the issue + // see https://youtrack.jetbrains.com/issue/IDEA-148280 + + // override fun collectSourceRoots(mavenProject: MavenProject, result: PairConsumer>) { + // for ((type, dir) in collectSourceDirectories(mavenProject)) { + // val jpsType: JpsModuleSourceRootType<*> = when (type) { + // SourceType.PROD -> JavaSourceRootType.SOURCE + // SourceType.TEST -> JavaSourceRootType.TEST_SOURCE + // } + // + // result.consume(dir, jpsType) + // } + // } + + private fun contributeSourceDirectories(mavenProject: MavenProject, module: Module, rootModel: MavenRootModelAdapter) { + val directories = collectSourceDirectories(mavenProject) + + val toBeAdded = directories.map { it.second }.toSet() + val state = module.kotlinImporterComponent + + for ((type, dir) in directories) { + if (rootModel.getSourceFolder(File(dir)) == null) { + val jpsType: JpsModuleSourceRootType<*> = when (type) { + SourceType.TEST -> JavaSourceRootType.TEST_SOURCE + SourceType.PROD -> JavaSourceRootType.SOURCE + } + + rootModel.addSourceFolder(dir, jpsType) + } + } + + state.addedSources.filter { it !in toBeAdded }.forEach { + rootModel.unregisterAll(it, true, true) + state.addedSources.remove(it) + } + state.addedSources.addAll(toBeAdded) + } + + private fun collectSourceDirectories(mavenProject: MavenProject): List> = + mavenProject.plugins.filter { it.isKotlinPlugin() }.flatMap { plugin -> + plugin.configurationElement.sourceDirectories().map { SourceType.PROD to it } + + plugin.executions.flatMap { execution -> execution.configurationElement.sourceDirectories().map { execution.sourceType() to it } } + }.distinct() +} + +private fun MavenPlugin.isKotlinPlugin() = groupId == KotlinPluginGroupId && artifactId == KotlinPluginArtifactId +private fun Element?.sourceDirectories(): List = this?.getChildren(KotlinPluginSourceDirsConfig)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim } ?: emptyList() +private fun MavenPlugin.Execution.sourceType() = + goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD } + .distinct() + .singleOrNull() ?: SourceType.PROD + +private fun isTestGoalName(goalName: String) = goalName.startsWith("test-") + +private enum class SourceType { + PROD, TEST +} + +@State(name = "AutoImportedSourceRoots", + storages = arrayOf( + Storage(id = "other", file = StoragePathMacros.MODULE_FILE) + )) +class KotlinImporterComponent : PersistentStateComponent { + class State(var directories: List = ArrayList()) + + val addedSources = Collections.synchronizedSet(HashSet()) + + override fun loadState(state: KotlinImporterComponent.State?) { + addedSources.clear() + if (state != null) { + addedSources.addAll(state.directories) + } + } + + override fun getState(): KotlinImporterComponent.State { + return KotlinImporterComponent.State(addedSources.sorted()) + } +} + +private val Module.kotlinImporterComponent: KotlinImporterComponent + get() = getComponent(KotlinImporterComponent::class.java) ?: throw IllegalStateException("No maven importer state configured") \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt new file mode 100644 index 00000000000..751268755cf --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt @@ -0,0 +1,391 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven + +import org.jetbrains.kotlin.idea.configuration.KotlinImporterComponent +import java.io.File + +class KotlinMavenImporterTest : MavenImportingTestCase() { + private val kotlinVersion = "1.0.0-beta-2423" + + override fun setUp() { + super.setUp() + repositoryPath = File(myDir, "repo").path + createStdProjectFolders() + } + + fun testSimpleKotlinProject() { + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + """) + + assertModules("project") + assertImporterStatePresent() + assertSources("project", "src/main/java") + } + + fun testWithSpecifiedSourceRoot() { + createProjectSubDir("src/main/kotlin") + + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + """) + + assertModules("project") + assertImporterStatePresent() + assertSources("project", "src/main/kotlin") + } + + fun testWithCustomSourceDirs() { + createProjectSubDirs("src/main/kotlin", "src/main/kotlin.jvm", "src/test/kotlin", "src/test/kotlin.jvm") + + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + compile + compile + + compile + + + + src/main/kotlin + src/main/kotlin.jvm + + + + + + test-compile + test-compile + + test-compile + + + + src/test/kotlin + src/test/kotlin.jvm + + + + + + + + """) + + assertModules("project") + assertImporterStatePresent() + + assertSources("project", "src/main/kotlin", "src/main/kotlin.jvm") + assertTestSources("project", "src/test/java", "src/test/kotlin", "src/test/kotlin.jvm") + } + + fun testReImportRemoveDir() { + createProjectSubDirs("src/main/kotlin", "src/main/kotlin.jvm", "src/test/kotlin", "src/test/kotlin.jvm") + + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + compile + compile + + compile + + + + src/main/kotlin + src/main/kotlin.jvm + + + + + + test-compile + test-compile + + test-compile + + + + src/test/kotlin + src/test/kotlin.jvm + + + + + + + + """) + + assertModules("project") + assertImporterStatePresent() + + assertSources("project", "src/main/kotlin", "src/main/kotlin.jvm") + assertTestSources("project", "src/test/java", "src/test/kotlin", "src/test/kotlin.jvm") + + // reimport + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + compile + compile + + compile + + + + src/main/kotlin + + + + + + test-compile + test-compile + + test-compile + + + + src/test/kotlin + src/test/kotlin.jvm + + + + + + + + """) + + assertSources("project", "src/main/kotlin") + assertTestSources("project", "src/test/java", "src/test/kotlin", "src/test/kotlin.jvm") + } + + fun testReImportAddDir() { + createProjectSubDirs("src/main/kotlin", "src/main/kotlin.jvm", "src/test/kotlin", "src/test/kotlin.jvm") + + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + compile + compile + + compile + + + + src/main/kotlin + + + + + + test-compile + test-compile + + test-compile + + + + src/test/kotlin + src/test/kotlin.jvm + + + + + + + + """) + + assertModules("project") + assertImporterStatePresent() + + assertSources("project", "src/main/kotlin") + assertTestSources("project", "src/test/java", "src/test/kotlin", "src/test/kotlin.jvm") + + // reimport + importProject(""" + test + project + 1.0.0 + + + + org.jetbrains.kotlin + kotlin-stdlib + $kotlinVersion + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + compile + compile + + compile + + + + src/main/kotlin + src/main/kotlin.jvm + + + + + + test-compile + test-compile + + test-compile + + + + src/test/kotlin + src/test/kotlin.jvm + + + + + + + + """) + + assertSources("project", "src/main/kotlin", "src/main/kotlin.jvm") + assertTestSources("project", "src/test/java", "src/test/kotlin", "src/test/kotlin.jvm") + } + + private fun assertImporterStatePresent() { + assertNotNull("Kotlin importer component is not present", myTestFixture.module.getComponent(KotlinImporterComponent::class.java)) + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java b/idea/tests/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java new file mode 100644 index 00000000000..d89262a94da --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/maven/MavenImportingTestCase.java @@ -0,0 +1,585 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven; + +import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TestDialog; +import com.intellij.openapi.util.AsyncResult; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.util.Consumer; +import com.intellij.util.PathUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.execution.*; +import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; +import org.jetbrains.idea.maven.project.*; +import org.jetbrains.idea.maven.server.MavenServerManager; +import org.jetbrains.jps.model.java.JavaResourceRootType; +import org.jetbrains.jps.model.java.JavaSourceRootProperties; +import org.jetbrains.jps.model.java.JavaSourceRootType; +import org.jetbrains.jps.model.module.JpsModuleSourceRootType; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class MavenImportingTestCase extends MavenTestCase { + protected MavenProjectsTree myProjectsTree; + protected MavenProjectsManager myProjectsManager; + private File myGlobalSettingsFile; + + @Override + protected void setUp() throws Exception { + VfsRootAccess.allowRootAccess(PathManager.getConfigPath()); + super.setUp(); + myGlobalSettingsFile = + MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().generalSettings.getEffectiveGlobalSettingsIoFile(); + if (myGlobalSettingsFile != null) { + VfsRootAccess.allowRootAccess(myGlobalSettingsFile.getAbsolutePath()); + } + } + + @Override + protected void setUpInWriteAction() throws Exception { + super.setUpInWriteAction(); + myProjectsManager = MavenProjectsManager.getInstance(myProject); + removeFromLocalRepository("test"); + } + + @Override + protected void tearDown() throws Exception { + try { + if (myGlobalSettingsFile != null) { + VfsRootAccess.disallowRootAccess(myGlobalSettingsFile.getAbsolutePath()); + } + VfsRootAccess.disallowRootAccess(PathManager.getConfigPath()); + Messages.setTestDialog(TestDialog.DEFAULT); + removeFromLocalRepository("test"); + FileUtil.delete(BuildManager.getInstance().getBuildSystemDirectory()); + } + finally { + super.tearDown(); + } + } + + protected void assertModules(String... expectedNames) { + Module[] actual = ModuleManager.getInstance(myProject).getModules(); + List actualNames = new ArrayList(); + + for (Module m : actual) { + actualNames.add(m.getName()); + } + + assertUnorderedElementsAreEqual(actualNames, expectedNames); + } + + protected void assertContentRoots(String moduleName, String... expectedRoots) { + List actual = new ArrayList(); + for (ContentEntry e : getContentRoots(moduleName)) { + actual.add(e.getUrl()); + } + + for (int i = 0; i < expectedRoots.length; i++) { + expectedRoots[i] = VfsUtil.pathToUrl(expectedRoots[i]); + } + + assertUnorderedPathsAreEqual(actual, Arrays.asList(expectedRoots)); + } + + protected void assertSources(String moduleName, String... expectedSources) { + doAssertContentFolders(moduleName, JavaSourceRootType.SOURCE, expectedSources); + } + + protected void assertGeneratedSources(String moduleName, String... expectedSources) { + ContentEntry contentRoot = getContentRoot(moduleName); + List folders = new ArrayList(); + for (SourceFolder folder : contentRoot.getSourceFolders(JavaSourceRootType.SOURCE)) { + JavaSourceRootProperties properties = folder.getJpsElement().getProperties(JavaSourceRootType.SOURCE); + assertNotNull(properties); + if (properties.isForGeneratedSources()) { + folders.add(folder); + } + } + doAssertContentFolders(contentRoot, folders, expectedSources); + } + + protected void assertResources(String moduleName, String... expectedSources) { + doAssertContentFolders(moduleName, JavaResourceRootType.RESOURCE, expectedSources); + } + + protected void assertTestSources(String moduleName, String... expectedSources) { + doAssertContentFolders(moduleName, JavaSourceRootType.TEST_SOURCE, expectedSources); + } + + protected void assertTestResources(String moduleName, String... expectedSources) { + doAssertContentFolders(moduleName, JavaResourceRootType.TEST_RESOURCE, expectedSources); + } + + protected void assertExcludes(String moduleName, String... expectedExcludes) { + ContentEntry contentRoot = getContentRoot(moduleName); + doAssertContentFolders(contentRoot, Arrays.asList(contentRoot.getExcludeFolders()), expectedExcludes); + } + + protected void assertContentRootExcludes(String moduleName, String contentRoot, String... expectedExcudes) { + ContentEntry root = getContentRoot(moduleName, contentRoot); + doAssertContentFolders(root, Arrays.asList(root.getExcludeFolders()), expectedExcudes); + } + + private void doAssertContentFolders(String moduleName, @NotNull JpsModuleSourceRootType rootType, String... expected) { + ContentEntry contentRoot = getContentRoot(moduleName); + doAssertContentFolders(contentRoot, contentRoot.getSourceFolders(rootType), expected); + } + + private static void doAssertContentFolders(ContentEntry e, final List folders, String... expected) { + List actual = new ArrayList(); + for (ContentFolder f : folders) { + String rootUrl = e.getUrl(); + String folderUrl = f.getUrl(); + + if (folderUrl.startsWith(rootUrl)) { + int length = rootUrl.length() + 1; + folderUrl = folderUrl.substring(Math.min(length, folderUrl.length())); + } + + actual.add(folderUrl); + } + + assertOrderedElementsAreEqual(actual, Arrays.asList(expected)); + } + + protected void assertModuleOutput(String moduleName, String output, String testOutput) { + CompilerModuleExtension e = getCompilerExtension(moduleName); + + assertFalse(e.isCompilerOutputPathInherited()); + assertEquals(output, getAbsolutePath(e.getCompilerOutputUrl())); + assertEquals(testOutput, getAbsolutePath(e.getCompilerOutputUrlForTests())); + } + + private static String getAbsolutePath(String path) { + path = VfsUtil.urlToPath(path); + path = PathUtil.getCanonicalPath(path); + return FileUtil.toSystemIndependentName(path); + } + + protected void assertProjectOutput(String module) { + assertTrue(getCompilerExtension(module).isCompilerOutputPathInherited()); + } + + protected CompilerModuleExtension getCompilerExtension(String module) { + ModuleRootManager m = getRootManager(module); + return CompilerModuleExtension.getInstance(m.getModule()); + } + + protected void assertModuleLibDep(String moduleName, String depName) { + assertModuleLibDep(moduleName, depName, null); + } + + protected void assertModuleLibDep(String moduleName, String depName, String classesPath) { + assertModuleLibDep(moduleName, depName, classesPath, null, null); + } + + protected void assertModuleLibDep(String moduleName, String depName, String classesPath, String sourcePath, String javadocPath) { + LibraryOrderEntry lib = getModuleLibDep(moduleName, depName); + + assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath)); + assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath)); + assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPath == null ? null : Collections.singletonList(javadocPath)); + } + + protected void assertModuleLibDep(String moduleName, + String depName, + List classesPaths, + List sourcePaths, + List javadocPaths) { + LibraryOrderEntry lib = getModuleLibDep(moduleName, depName); + + assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths); + assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePaths); + assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPaths); + } + + private static void assertModuleLibDepPath(LibraryOrderEntry lib, OrderRootType type, List paths) { + if (paths == null) return; + assertUnorderedPathsAreEqual(Arrays.asList(lib.getRootUrls(type)), paths); + // also check the library because it may contain slight different set of urls (e.g. with duplicates) + assertUnorderedPathsAreEqual(Arrays.asList(lib.getLibrary().getUrls(type)), paths); + } + + protected void assertModuleLibDepScope(String moduleName, String depName, DependencyScope scope) { + LibraryOrderEntry dep = getModuleLibDep(moduleName, depName); + assertEquals(scope, dep.getScope()); + } + + private LibraryOrderEntry getModuleLibDep(String moduleName, String depName) { + return getModuleDep(moduleName, depName, LibraryOrderEntry.class); + } + + protected void assertModuleLibDeps(String moduleName, String... expectedDeps) { + assertModuleDeps(moduleName, LibraryOrderEntry.class, expectedDeps); + } + + protected void assertExportedDeps(String moduleName, String... expectedDeps) { + final List actual = new ArrayList(); + + getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly().process(new RootPolicy() { + @Override + public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) { + actual.add(e.getModuleName()); + return null; + } + + @Override + public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) { + actual.add(e.getLibraryName()); + return null; + } + }, null); + + assertOrderedElementsAreEqual(actual, expectedDeps); + } + + protected void assertModuleModuleDeps(String moduleName, String... expectedDeps) { + assertModuleDeps(moduleName, ModuleOrderEntry.class, expectedDeps); + } + + private void assertModuleDeps(String moduleName, Class clazz, String... expectedDeps) { + assertOrderedElementsAreEqual(collectModuleDepsNames(moduleName, clazz), expectedDeps); + } + + protected void assertModuleModuleDepScope(String moduleName, String depName, DependencyScope scope) { + ModuleOrderEntry dep = getModuleModuleDep(moduleName, depName); + assertEquals(scope, dep.getScope()); + } + + private ModuleOrderEntry getModuleModuleDep(String moduleName, String depName) { + return getModuleDep(moduleName, depName, ModuleOrderEntry.class); + } + + private List collectModuleDepsNames(String moduleName, Class clazz) { + List actual = new ArrayList(); + + for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) { + if (clazz.isInstance(e)) { + actual.add(e.getPresentableName()); + } + } + return actual; + } + + private T getModuleDep(String moduleName, String depName, Class clazz) { + T dep = null; + + for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) { + if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) { + dep = (T)e; + } + } + assertNotNull("Dependency not found: " + depName + + "\namong: " + collectModuleDepsNames(moduleName, clazz), + dep); + return dep; + } + + public void assertProjectLibraries(String... expectedNames) { + List actualNames = new ArrayList(); + for (Library each : ProjectLibraryTable.getInstance(myProject).getLibraries()) { + String name = each.getName(); + actualNames.add(name == null ? "" : name); + } + assertUnorderedElementsAreEqual(actualNames, expectedNames); + } + + protected void assertModuleGroupPath(String moduleName, String... expected) { + String[] path = ModuleManager.getInstance(myProject).getModuleGroupPath(getModule(moduleName)); + + if (expected.length == 0) { + assertNull(path); + } + else { + assertNotNull(path); + assertOrderedElementsAreEqual(Arrays.asList(path), expected); + } + } + + protected Module getModule(final String name) { + AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); + try { + Module m = ModuleManager.getInstance(myProject).findModuleByName(name); + assertNotNull("Module " + name + " not found", m); + return m; + } + finally { + accessToken.finish(); + } + } + + private ContentEntry getContentRoot(String moduleName) { + ContentEntry[] ee = getContentRoots(moduleName); + List roots = new ArrayList(); + for (ContentEntry e : ee) { + roots.add(e.getUrl()); + } + + String message = "Several content roots found: [" + StringUtil.join(roots, ", ") + "]"; + assertEquals(message, 1, ee.length); + + return ee[0]; + } + + private ContentEntry getContentRoot(String moduleName, String path) { + for (ContentEntry e : getContentRoots(moduleName)) { + if (e.getUrl().equals(VfsUtil.pathToUrl(path))) return e; + } + throw new AssertionError("content root not found"); + } + + public ContentEntry[] getContentRoots(String moduleName) { + return getRootManager(moduleName).getContentEntries(); + } + + private ModuleRootManager getRootManager(String module) { + return ModuleRootManager.getInstance(getModule(module)); + } + + protected void importProject(@NonNls String xml) throws IOException { + createProjectPom(xml); + importProject(); + } + + protected void importProject() { + importProjectWithProfiles(); + } + + protected void importProjectWithProfiles(String... profiles) { + doImportProjects(true, Collections.singletonList(myProjectPom), profiles); + } + + protected void importProject(VirtualFile file) { + importProjects(file); + } + + protected void importProjects(VirtualFile... files) { + doImportProjects(true, Arrays.asList(files)); + } + + protected void importProjectWithMaven3(@NonNls String xml) throws IOException { + createProjectPom(xml); + importProjectWithMaven3(); + } + + protected void importProjectWithMaven3() { + importProjectWithMaven3WithProfiles(); + } + + protected void importProjectWithMaven3WithProfiles(String... profiles) { + doImportProjects(false, Collections.singletonList(myProjectPom), profiles); + } + + private void doImportProjects(boolean useMaven2, final List files, String... profiles) { + MavenServerManager.getInstance().setUseMaven2(useMaven2); + initProjectsManager(false); + + readProjects(files, profiles); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.waitForResolvingCompletion(); + myProjectsManager.scheduleImportInTests(files); + myProjectsManager.importProjects(); + } + }); + + for (MavenProject each : myProjectsTree.getProjects()) { + if (each.hasReadingProblems()) { + System.out.println(each + " has problems: " + each.getProblems()); + } + } + } + + protected void readProjects(List files, String... profiles) { + myProjectsManager.resetManagedFilesAndProfilesInTests(files, new MavenExplicitProfiles(Arrays.asList(profiles))); + waitForReadingCompletion(); + } + + protected void updateProjectsAndImport(VirtualFile... files) { + readProjects(files); + myProjectsManager.performScheduledImportInTests(); + } + + protected void initProjectsManager(boolean enableEventHandling) { + myProjectsManager.initForTests(); + myProjectsTree = myProjectsManager.getProjectsTreeForTests(); + if (enableEventHandling) myProjectsManager.listenForExternalChanges(); + } + + protected void scheduleResolveAll() { + myProjectsManager.scheduleResolveAllInTests(); + } + + protected void waitForReadingCompletion() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + myProjectsManager.waitForReadingCompletion(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + protected void readProjects() { + readProjects(myProjectsManager.getProjectsFiles()); + } + + protected void readProjects(VirtualFile... files) { + List projects = new ArrayList(); + for (VirtualFile each : files) { + projects.add(myProjectsManager.findProject(each)); + } + myProjectsManager.forceUpdateProjects(projects); + waitForReadingCompletion(); + } + + protected void resolveDependenciesAndImport() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.waitForResolvingCompletion(); + myProjectsManager.performScheduledImportInTests(); + } + }); + } + + protected void resolveFoldersAndImport() { + myProjectsManager.scheduleFoldersResolveForAllProjects(); + myProjectsManager.waitForFoldersResolvingCompletion(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + myProjectsManager.performScheduledImportInTests(); + } + }); + } + + protected void resolvePlugins() { + myProjectsManager.waitForPluginsResolvingCompletion(); + } + + protected void downloadArtifacts() { + downloadArtifacts(myProjectsManager.getProjects(), null); + } + + protected MavenArtifactDownloader.DownloadResult downloadArtifacts(Collection projects, + List artifacts) { + final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1]; + + AsyncResult result = new AsyncResult(); + result.doWhenDone(new Consumer() { + @Override + public void consume(MavenArtifactDownloader.DownloadResult unresolvedArtifacts) { + unresolved[0] = unresolvedArtifacts; + } + }); + + myProjectsManager.scheduleArtifactsDownloading(projects, artifacts, true, true, result); + myProjectsManager.waitForArtifactsDownloadingCompletion(); + + return unresolved[0]; + } + + protected void performPostImportTasks() { + myProjectsManager.waitForPostImportTasksCompletion(); + } + + protected void executeGoal(String relativePath, String goal) { + VirtualFile dir = myProjectRoot.findFileByRelativePath(relativePath); + + MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), Collections.emptyList()); + MavenRunnerSettings rs = new MavenRunnerSettings(); + MavenExecutor e = new MavenExternalExecutor(myProject, rp, getMavenGeneralSettings(), rs, new SoutMavenConsole()); + + e.execute(new EmptyProgressIndicator()); + } + + protected void removeFromLocalRepository(String relativePath) throws IOException { + FileUtil.delete(new File(getRepositoryPath(), relativePath)); + } + + protected void setupJdkForModules(String... moduleNames) { + for (String each : moduleNames) { + setupJdkForModule(each); + } + } + + protected Sdk setupJdkForModule(final String moduleName) { + final Sdk sdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk(); + ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk); + return sdk; + } + + protected static Sdk createJdk(String versionName) { + return IdeaTestUtil.getMockJdk17(versionName); + } + + protected static AtomicInteger configConfirmationForYesAnswer() { + final AtomicInteger counter = new AtomicInteger(); + Messages.setTestDialog(new TestDialog() { + @Override + public int show(String message) { + counter.set(counter.get() + 1); + return 0; + } + }); + return counter; + } + + protected static AtomicInteger configConfirmationForNoAnswer() { + final AtomicInteger counter = new AtomicInteger(); + Messages.setTestDialog(new TestDialog() { + @Override + public int show(String message) { + counter.set(counter.get() + 1); + return 1; + } + }); + return counter; + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/maven/MavenTestCase.java b/idea/tests/org/jetbrains/kotlin/idea/maven/MavenTestCase.java new file mode 100644 index 00000000000..20ee6776a5f --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/maven/MavenTestCase.java @@ -0,0 +1,617 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.UsefulTestCase; +import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.util.ui.UIUtil; +import gnu.trove.THashSet; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.indices.MavenIndicesManager; +import org.jetbrains.idea.maven.project.*; +import org.jetbrains.idea.maven.utils.MavenProgressIndicator; + +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; + +public abstract class MavenTestCase extends UsefulTestCase { + protected static final MavenConsole NULL_MAVEN_CONSOLE = new NullMavenConsole(); + // should not be static + protected static MavenProgressIndicator EMPTY_MAVEN_PROCESS = new MavenProgressIndicator(new EmptyProgressIndicator()); + + private File ourTempDir; + + protected IdeaProjectTestFixture myTestFixture; + + protected Project myProject; + + protected File myDir; + protected VirtualFile myProjectRoot; + + protected VirtualFile myProjectPom; + protected List myAllPoms = new ArrayList(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + + ensureTempDirCreated(); + + myDir = new File(ourTempDir, getTestName(false)); + FileUtil.ensureExists(myDir); + + setUpFixtures(); + + myProject = myTestFixture.getProject(); + + MavenWorkspaceSettingsComponent.getInstance(myProject).loadState(new MavenWorkspaceSettings()); + + String home = getTestMavenHome(); + if (home != null) { + getMavenGeneralSettings().setMavenHome(home); + } + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + restoreSettingsFile(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + setUpInWriteAction(); + } + catch (Throwable e) { + try { + tearDown(); + } + catch (Exception e1) { + e1.printStackTrace(); + } + throw new RuntimeException(e); + } + } + }); + } + }); + + } + + private void ensureTempDirCreated() throws IOException { + if (ourTempDir != null) return; + + ourTempDir = new File(FileUtil.getTempDirectory(), "mavenTests"); + FileUtil.delete(ourTempDir); + FileUtil.ensureExists(ourTempDir); + } + + protected void setUpFixtures() throws Exception { + myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).getFixture(); + myTestFixture.setUp(); + } + + protected void setUpInWriteAction() throws Exception { + File projectDir = new File(myDir, "project"); + projectDir.mkdirs(); + myProjectRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectDir); + } + + @Override + protected void tearDown() throws Exception { + try { + myProject = null; + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + tearDownFixtures(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + + MavenIndicesManager.getInstance().clear(); + } + finally { + super.tearDown(); + FileUtil.delete(myDir); + // cannot use reliably the result of the com.intellij.openapi.util.io.FileUtil.delete() method + // because com.intellij.openapi.util.io.FileUtilRt.deleteRecursivelyNIO() does not honor this contract + if (myDir.exists()) { + System.err.println("Cannot delete " + myDir); + //printDirectoryContent(myDir); + myDir.deleteOnExit(); + } + resetClassFields(getClass()); + } + } + + private static void printDirectoryContent(File dir) { + File[] files = dir.listFiles(); + if (files == null) return; + + for (File file : files) { + System.out.println(file.getAbsolutePath()); + + if (file.isDirectory()) { + printDirectoryContent(file); + } + } + } + + protected void tearDownFixtures() throws Exception { + myTestFixture.tearDown(); + myTestFixture = null; + } + + private void resetClassFields(final Class aClass) { + if (aClass == null) return; + + final Field[] fields = aClass.getDeclaredFields(); + for (Field field : fields) { + final int modifiers = field.getModifiers(); + if ((modifiers & Modifier.FINAL) == 0 + && (modifiers & Modifier.STATIC) == 0 + && !field.getType().isPrimitive()) { + field.setAccessible(true); + try { + field.set(this, null); + } + catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + if (aClass == MavenTestCase.class) return; + resetClassFields(aClass.getSuperclass()); + } + + @Override + protected void runTest() throws Throwable { + try { + if (runInWriteAction()) { + new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + MavenTestCase.super.runTest(); + } + }.executeSilently().throwException(); + } + else { + MavenTestCase.super.runTest(); + } + } + catch (Exception throwable) { + Throwable each = throwable; + do { + if (each instanceof HeadlessException) { + printIgnoredMessage("Doesn't work in Headless environment"); + return; + } + } + while ((each = each.getCause()) != null); + throw throwable; + } + } + + @Override + protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { + runnable.run(); + } + + protected boolean runInWriteAction() { + return false; + } + + protected static String getRoot() { + if (SystemInfo.isWindows) return "c:"; + return ""; + } + + protected static String getEnvVar() { + if (SystemInfo.isWindows) return "TEMP"; + else if (SystemInfo.isLinux) return "HOME"; + return "TMPDIR"; + } + + protected MavenGeneralSettings getMavenGeneralSettings() { + return MavenProjectsManager.getInstance(myProject).getGeneralSettings(); + } + + protected MavenImportingSettings getMavenImporterSettings() { + return MavenProjectsManager.getInstance(myProject).getImportingSettings(); + } + + protected String getRepositoryPath() { + String path = getRepositoryFile().getPath(); + return FileUtil.toSystemIndependentName(path); + } + + protected File getRepositoryFile() { + return getMavenGeneralSettings().getEffectiveLocalRepository(); + } + + protected void setRepositoryPath(String path) { + getMavenGeneralSettings().setLocalRepository(path); + } + + protected String getProjectPath() { + return myProjectRoot.getPath(); + } + + protected String getParentPath() { + return myProjectRoot.getParent().getPath(); + } + + protected String pathFromBasedir(String relPath) { + return pathFromBasedir(myProjectRoot, relPath); + } + + protected static String pathFromBasedir(VirtualFile root, String relPath) { + return FileUtil.toSystemIndependentName(root.getPath() + "/" + relPath); + } + + protected VirtualFile updateSettingsXml(String content) throws IOException { + return updateSettingsXmlFully(createSettingsXmlContent(content)); + } + + protected VirtualFile updateSettingsXmlFully(@NonNls @Language("XML") String content) throws IOException { + File ioFile = new File(myDir, "settings.xml"); + ioFile.createNewFile(); + VirtualFile f = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile); + setFileContent(f, content, true); + getMavenGeneralSettings().setUserSettingsFile(f.getPath()); + return f; + } + + protected void deleteSettingsXml() throws IOException { + new WriteCommandAction.Simple(myProject) { + @Override + protected void run() throws Throwable { + VirtualFile f = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(myDir, "settings.xml")); + if (f != null) f.delete(this); + } + }.execute().throwException(); + } + + private static String createSettingsXmlContent(String content) { + String mirror = System.getProperty("idea.maven.test.mirror", + // use JB maven proxy server for internal use by default, see details at + // https://confluence.jetbrains.com/display/JBINT/Maven+proxy+server + "http://maven.labs.intellij.net/repo"); + return "" + + content + + "" + + " " + + " jb-central-proxy" + + " " + mirror + "" + + " external:*" + + " " + + "" + + ""; + } + + protected void restoreSettingsFile() throws IOException { + updateSettingsXml(""); + } + + protected Module createModule(String name) throws IOException { + return createModule(name, StdModuleTypes.JAVA); + } + + protected Module createModule(final String name, final ModuleType type) throws IOException { + return new WriteCommandAction(myProject) { + @Override + protected void run(@NotNull Result moduleResult) throws Throwable { + VirtualFile f = createProjectSubFile(name + "/" + name + ".iml"); + Module module = ModuleManager.getInstance(myProject).newModule(f.getPath(), type.getId()); + PsiTestUtil.addContentRoot(module, f.getParent()); + moduleResult.setResult(module); + } + }.execute().getResultObject(); + } + + protected VirtualFile createProjectPom(@NonNls String xml) throws IOException { + return myProjectPom = createPomFile(myProjectRoot, xml); + } + + protected VirtualFile createModulePom(String relativePath, String xml) throws IOException { + return createPomFile(createProjectSubDir(relativePath), xml); + } + + protected VirtualFile createPomFile(final VirtualFile dir, String xml) throws IOException { + VirtualFile f = dir.findChild("pom.xml"); + if (f == null) { + f = new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + VirtualFile res = dir.createChildData(null, "pom.xml"); + result.setResult(res); + } + }.execute().getResultObject(); + myAllPoms.add(f); + } + setFileContent(f, createPomXml(xml), true); + return f; + } + + @NonNls @Language(value="XML") + public static String createPomXml(@NonNls @Language(value="XML", prefix="", suffix="") String xml) { + return "" + + "" + + " 4.0.0" + + xml + + ""; + } + + protected VirtualFile createProfilesXmlOldStyle(String xml) throws IOException { + return createProfilesFile(myProjectRoot, xml, true); + } + + protected VirtualFile createProfilesXmlOldStyle(String relativePath, String xml) throws IOException { + return createProfilesFile(createProjectSubDir(relativePath), xml, true); + } + + protected VirtualFile createProfilesXml(String xml) throws IOException { + return createProfilesFile(myProjectRoot, xml, false); + } + + protected VirtualFile createProfilesXml(String relativePath, String xml) throws IOException { + return createProfilesFile(createProjectSubDir(relativePath), xml, false); + } + + private static VirtualFile createProfilesFile(VirtualFile dir, String xml, boolean oldStyle) throws IOException { + return createProfilesFile(dir, createValidProfiles(xml, oldStyle)); + } + + protected VirtualFile createFullProfilesXml(String content) throws IOException { + return createProfilesFile(myProjectRoot, content); + } + + protected VirtualFile createFullProfilesXml(String relativePath, String content) throws IOException { + return createProfilesFile(createProjectSubDir(relativePath), content); + } + + private static VirtualFile createProfilesFile(final VirtualFile dir, String content) throws IOException { + VirtualFile f = dir.findChild("profiles.xml"); + if (f == null) { + f = new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + VirtualFile res = dir.createChildData(null, "profiles.xml"); + result.setResult(res); + } + }.execute().getResultObject(); + } + setFileContent(f, content, true); + return f; + } + + @Language("XML") + private static String createValidProfiles(String xml, boolean oldStyle) { + if (oldStyle) { + return "" + + "" + + xml + + ""; + } + return "" + + "" + + "" + + xml + + "" + + ""; + } + + protected void deleteProfilesXml() throws IOException { + new WriteCommandAction.Simple(myProject) { + @Override + protected void run() throws Throwable { + VirtualFile f = myProjectRoot.findChild("profiles.xml"); + if (f != null) f.delete(this); + } + }.execute().throwException(); + } + + protected void createStdProjectFolders() { + createProjectSubDirs("src/main/java", + "src/main/resources", + "src/test/java", + "src/test/resources"); + } + + protected void createProjectSubDirs(String... relativePaths) { + for (String path : relativePaths) { + createProjectSubDir(path); + } + } + + protected VirtualFile createProjectSubDir(String relativePath) { + File f = new File(getProjectPath(), relativePath); + f.mkdirs(); + return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f); + } + + protected VirtualFile createProjectSubFile(String relativePath) throws IOException { + File f = new File(getProjectPath(), relativePath); + f.getParentFile().mkdirs(); + f.createNewFile(); + return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f); + } + + protected VirtualFile createProjectSubFile(String relativePath, String content) throws IOException { + VirtualFile file = createProjectSubFile(relativePath); + setFileContent(file, content, false); + return file; + } + + private static void setFileContent(final VirtualFile file, final String content, final boolean advanceStamps) throws IOException { + new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + if (advanceStamps) { + file.setBinaryContent(content.getBytes(), -1, file.getTimeStamp() + 4000); + } + else { + file.setBinaryContent(content.getBytes(), file.getModificationStamp(), file.getTimeStamp()); + } + } + }.execute().getResultObject(); + } + + protected static void assertOrderedElementsAreEqual(Collection actual, Collection expected) { + assertOrderedElementsAreEqual(actual, expected.toArray()); + } + + protected static void assertUnorderedElementsAreEqual(Collection actual, Collection expected) { + assertEquals(new HashSet(expected), new HashSet(actual)); + } + protected static void assertUnorderedPathsAreEqual(Collection actual, Collection expected) { + assertEquals(new SetWithToString(new THashSet(expected, FileUtil.PATH_HASHING_STRATEGY)), + new SetWithToString(new THashSet(actual, FileUtil.PATH_HASHING_STRATEGY))); + } + + protected static void assertUnorderedElementsAreEqual(T[] actual, T... expected) { + assertUnorderedElementsAreEqual(Arrays.asList(actual), expected); + } + + protected static void assertUnorderedElementsAreEqual(Collection actual, T... expected) { + assertUnorderedElementsAreEqual(actual, Arrays.asList(expected)); + } + + protected static void assertOrderedElementsAreEqual(Collection actual, T... expected) { + String s = "\nexpected: " + Arrays.asList(expected) + "\nactual: " + new ArrayList(actual); + assertEquals(s, expected.length, actual.size()); + + List actualList = new ArrayList(actual); + for (int i = 0; i < expected.length; i++) { + T expectedElement = expected[i]; + U actualElement = actualList.get(i); + assertEquals(s, expectedElement, actualElement); + } + } + + protected static void assertContain(List actual, T... expected) { + List expectedList = Arrays.asList(expected); + assertTrue("expected: " + expectedList + "\n" + "actual: " + actual.toString(), actual.containsAll(expectedList)); + } + + protected static void assertDoNotContain(List actual, T... expected) { + List actualCopy = new ArrayList(actual); + actualCopy.removeAll(Arrays.asList(expected)); + assertEquals(actual.toString(), actualCopy.size(), actual.size()); + } + + protected boolean ignore() { + printIgnoredMessage(null); + return true; + } + + protected boolean hasMavenInstallation() { + boolean result = getTestMavenHome() != null; + if (!result) printIgnoredMessage("Maven installation not found"); + return result; + } + + private void printIgnoredMessage(String message) { + String toPrint = "Ignored"; + if (message != null) { + toPrint += ", because " + message; + } + toPrint += ": " + getClass().getSimpleName() + "." + getName(); + System.out.println(toPrint); + } + + private static String getTestMavenHome() { + return System.getProperty("idea.maven.test.home"); + } + + private static class SetWithToString extends AbstractSet { + + private final Set myDelegate; + + public SetWithToString(@NotNull Set delegate) { + myDelegate = delegate; + } + + @Override + public int size() { + return myDelegate.size(); + } + + @Override + public boolean contains(Object o) { + return myDelegate.contains(o); + } + + @NotNull + @Override + public Iterator iterator() { + return myDelegate.iterator(); + } + + @Override + public boolean containsAll(Collection c) { + return myDelegate.containsAll(c); + } + + @Override + public boolean equals(Object o) { + return myDelegate.equals(o); + } + + @Override + public int hashCode() { + return myDelegate.hashCode(); + } + } + +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/maven/NullMavenConsole.java b/idea/tests/org/jetbrains/kotlin/idea/maven/NullMavenConsole.java new file mode 100644 index 00000000000..70688d9325a --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/maven/NullMavenConsole.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven; + +import com.intellij.execution.process.ProcessHandler; +import org.jetbrains.idea.maven.execution.MavenExecutionOptions; +import org.jetbrains.idea.maven.project.MavenConsole; + +public class NullMavenConsole extends MavenConsole { + public NullMavenConsole() { + super(MavenExecutionOptions.LoggingLevel.DISABLED, false); + } + + @Override + public boolean canPause() { + return false; + } + + @Override + public boolean isOutputPaused() { + return false; + } + + @Override + public void setOutputPaused(boolean outputPaused) { + } + + @Override + public void attachToProcess(ProcessHandler processHandler) { + } + + @Override + protected void doPrint(String text, MavenConsole.OutputType type) { + } +}