From 9ac1de6b44ddc330c8224b2886da4f82e0864782 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 16 Jan 2018 17:36:43 +0300 Subject: [PATCH] build scripts: allow running JUnit configurations configured in the IDE Some tests required specific JVM options or depends on project artifacts so they need to be started in a special way. It's simpler to specify these settings in a JUnit run configuration configured in the project. Currently such tests are run on TeamCity using its own 'IntelliJ IDEA Project' runner and this often causes problems because TeamCity uses an older version of JPS, we need to download dependencies for such configurations in a different way, it isn't possible to reuse compiled classes, etc. Now it's possible to pass run configuration names via 'intellij.build.test.configurations' system property and corresponding run configurations will be executed using the common build scripts infrastructure. --- .idea/modules.xml | 1 + .../intellij/build/TestingOptions.groovy | 12 +- .../JUnitRunConfigurationProperties.groovy | 81 +++++++++ .../build/impl/TestingTasksImpl.groovy | 165 ++++++++++++------ .../tests/platform-build-scripts-tests.iml | 15 ++ .../build/runConfigurations/test_class.xml | 23 +++ .../build/runConfigurations/test_package.xml | 19 ++ .../build/runConfigurations/test_pattern.xml | 27 +++ .../JUnitRunConfigurationPropertiesTest.kt | 46 +++++ .../intellij/build/MockBuildMessages.kt | 55 ++++++ 10 files changed, 393 insertions(+), 51 deletions(-) create mode 100644 platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JUnitRunConfigurationProperties.groovy create mode 100644 platform/build-scripts/tests/platform-build-scripts-tests.iml create mode 100644 platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_class.xml create mode 100644 platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_package.xml create mode 100644 platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_pattern.xml create mode 100644 platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/JUnitRunConfigurationPropertiesTest.kt create mode 100644 platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/MockBuildMessages.kt diff --git a/.idea/modules.xml b/.idea/modules.xml index 049379723553..bb30ded81900 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -43,6 +43,7 @@ + diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy index 897175707c9b..9339db332d4a 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/TestingOptions.groovy @@ -31,10 +31,17 @@ class TestingOptions { String testGroups = System.getProperty("intellij.build.test.groups", OLD_TEST_GROUP) /** - * Semicolon-separated patterns for test class names which need to be executed. Wildcard '*' is supported. + * Semicolon-separated patterns for test class names which need to be executed. Wildcard '*' is supported. If this option is specified, + * {@link #testGroups} will be ignored. */ String testPatterns = System.getProperty("intellij.build.test.patterns", OLD_TEST_PATTERNS) + /** + * Semicolon-separated names of JUnit run configurations in the project which need to be executed. If this option is specified, + * {@link #testGroups} and {@link #testPatterns} will be ignored. + */ + String testConfigurations = System.getProperty("intellij.build.test.configurations") + /** * Specifies components from which product will be used to run tests, by default IDEA Ultimate will be used. */ @@ -70,7 +77,8 @@ class TestingOptions { */ String customJrePath = System.getProperty("intellij.build.test.jre") - private static final String OLD_TEST_GROUP = System.getProperty("idea.test.group", "ALL_EXCLUDE_DEFINED") + public static final String ALL_EXCLUDE_DEFINED_GROUP = "ALL_EXCLUDE_DEFINED" + private static final String OLD_TEST_GROUP = System.getProperty("idea.test.group", ALL_EXCLUDE_DEFINED_GROUP) private static final String OLD_TEST_PATTERNS = System.getProperty("idea.test.patterns") private static final String OLD_PLATFORM_PREFIX = System.getProperty("idea.platform.prefix") private static final int OLD_DEBUG_PORT = SystemProperties.getIntProperty("debug.port", -1) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JUnitRunConfigurationProperties.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JUnitRunConfigurationProperties.groovy new file mode 100644 index 000000000000..86fa6bda1c2e --- /dev/null +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/JUnitRunConfigurationProperties.groovy @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ +package org.jetbrains.intellij.build.impl + +import com.intellij.openapi.util.io.FileUtil +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import org.jetbrains.intellij.build.BuildMessages + +@CompileStatic +class JUnitRunConfigurationProperties { + final String name + final String moduleName + final List testClassPatterns + final List vmParameters + final List requiredArtifacts + + static JUnitRunConfigurationProperties findRunConfiguration(String projectHome, String name, BuildMessages messages) { + def file = new File(projectHome, ".idea/runConfigurations/${FileUtil.sanitizeFileName(name)}.xml") + if (!file.exists()) { + messages.error("Cannot find run configurations: $file doesn't exist") + } + + loadRunConfiguration(file, messages) + } + + @SuppressWarnings(["GrUnresolvedAccess", "GroovyAssignabilityCheck"]) + @CompileDynamic + static JUnitRunConfigurationProperties loadRunConfiguration(File file, BuildMessages messages) { + def root = new XmlParser().parse(file) + def configuration = first(root.configuration) + if (configuration == null) { + messages.error("Cannot load configuration from '$file.name': 'configuration' tag is not found") + } + if (configuration.@type != "JUnit") { + messages.error("Cannot load configuration from '$file.name': only JUnit run configuration are supported") + } + + String moduleName = first(configuration.module)?.@name + if (moduleName == null) { + messages.error("Cannot run configuration from '$file.name': module name is not specified") + } + Map options = configuration.option?.collectEntries { [it.@name, it.@value] } + def testKind = options["TEST_OBJECT"] + List testClassPatterns + if (testKind == "class") { + testClassPatterns = [options["MAIN_CLASS_NAME"]] + } + else if (testKind == "package") { + testClassPatterns = [options["PACKAGE_NAME"] + ".*"] + } + else if (testKind == "pattern") { + testClassPatterns = first(configuration?.patterns)?.pattern?.collect { it.@testClass } + } + else { + messages.error("Cannot run $file.name configuration: '${testKind}' test kind is not supported") + testClassPatterns = [] + } + + List requiredArtifacts = + first(configuration.method)?.option?. + find { it.@name == "BuildArtifacts" && it.@enabled == "true" }?. + artifact?.collect { it.@name } ?: [] + + def vmParameters = options["VM_PARAMETERS"].tokenize() + return new JUnitRunConfigurationProperties(configuration.@name, moduleName, testClassPatterns, vmParameters, requiredArtifacts) + } + + private static T first(Collection collection) { + collection == null || collection.isEmpty() ? null : collection.first() + } + + JUnitRunConfigurationProperties(String name, String moduleName, List testClassPatterns, List vmParameters, List requiredArtifacts) { + this.name = name + this.moduleName = moduleName + this.testClassPatterns = testClassPatterns + this.requiredArtifacts = requiredArtifacts + this.vmParameters = vmParameters + } +} diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy index 1114678c694f..49ee02534aa3 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/TestingTasksImpl.groovy @@ -18,7 +18,6 @@ package org.jetbrains.intellij.build.impl import com.intellij.execution.CommandLineWrapperUtil import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtilRt -import com.intellij.openapi.util.text.StringUtil import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.apache.tools.ant.AntClassLoader @@ -32,7 +31,6 @@ import org.jetbrains.jps.util.JpsPathUtil import java.util.function.Predicate import java.util.jar.Manifest - /** * @author nik */ @@ -48,16 +46,126 @@ class TestingTasksImpl extends TestingTasks { @Override void runTests(List additionalJvmOptions, String defaultMainModule, Predicate rootExcludeCondition) { + checkOptions() + def compilationTasks = CompilationTasks.create(context) - if (options.mainModule != null) { + def runConfigurations = options.testConfigurations?.split(";")?.collect { String name -> + JUnitRunConfigurationProperties.findRunConfiguration(context.paths.projectHome, name, context.messages) + } + if (runConfigurations != null) { + compilationTasks.compileModules(["tests_bootstrap"], ["platform-build-scripts"] + runConfigurations.collect { it.moduleName }) + compilationTasks.buildProjectArtifacts(runConfigurations.collectMany {it.requiredArtifacts}) + } + else if (options.mainModule != null) { compilationTasks.compileModules(["tests_bootstrap"], [options.mainModule, "platform-build-scripts"]) } else { compilationTasks.compileAllModulesAndTests() } + setupTestingDependencies() + def remoteDebugJvmOptions = System.getProperty("teamcity.remote-debug.jvm.options") + if (remoteDebugJvmOptions != null) { + debugTests(remoteDebugJvmOptions, additionalJvmOptions, defaultMainModule, rootExcludeCondition) + } + else if (runConfigurations != null) { + runTestsFromRunConfigurations(additionalJvmOptions, runConfigurations) + } + else { + runTestsFromGroupsAndPatterns(additionalJvmOptions, defaultMainModule, rootExcludeCondition) + } + } + + private void checkOptions() { + if (options.testConfigurations != null) { + if (options.testPatterns != null) { + context.messages.warning("'intellij.build.test.configurations' option is specified so 'intellij.build.test.patterns' will be ignored.") + } + if (options.testGroups != TestingOptions.ALL_EXCLUDE_DEFINED_GROUP) { + context.messages.warning("'intellij.build.test.configurations' option is specified so 'intellij.build.test.groups' will be ignored.") + } + if (options.testConfigurations != null && options.mainModule != null) { + context.messages.warning("'intellij.build.test.configurations' option is specified so 'intellij.build.test.main.module' will be ignored.") + } + } + else if (options.testPatterns != null && options.testGroups != TestingOptions.ALL_EXCLUDE_DEFINED_GROUP) { + context.messages.warning("'intellij.build.test.patterns' option is specified so 'intellij.build.test.groups' will be ignored.") + } + } + + private void runTestsFromRunConfigurations(List additionalJvmOptions, List runConfigurations) { + runConfigurations.each { configuration -> + context.messages.block("Run '${configuration.name}' run configuration") { + runTestsFromRunConfiguration(configuration, additionalJvmOptions) + } + } + } + + private void runTestsFromRunConfiguration(JUnitRunConfigurationProperties runConfigurationProperties, List additionalJvmOptions) { + context.messages.progress("Running '${runConfigurationProperties.name}' run configuration") + List filteredVmOptions = removeStandardJvmOptions(runConfigurationProperties.vmParameters) + runTestsProcess(runConfigurationProperties.moduleName, null, runConfigurationProperties.testClassPatterns.join(";"), + filteredVmOptions + additionalJvmOptions, [:], false) + } + + private static List removeStandardJvmOptions(List vmOptions) { + def ignoredPrefixes = [ + "-ea", "-XX:+HeapDumpOnOutOfMemoryError", + "-Xbootclasspath", + "-Xmx", "-Xms", + "-Didea.system.path=", "-Didea.config.path=", "-Didea.home.path=" + ] + vmOptions.findAll { option -> ignoredPrefixes.every { !option.startsWith(it) } } + } + + private void runTestsFromGroupsAndPatterns(List additionalJvmOptions, String defaultMainModule, Predicate rootExcludeCondition) { + Map additionalSystemProperties = [:] def mainModule = options.mainModule ?: defaultMainModule + if (rootExcludeCondition != null) { + List excludedModules = context.project.modules.findAll { + List contentRoots = it.contentRootsList.urls + !contentRoots.isEmpty() && rootExcludeCondition.test(JpsPathUtil.urlToFile(contentRoots.first())) + } + List excludedRoots = excludedModules.collectMany { + [context.getModuleOutputPath(it), context.getModuleTestsOutputPath(it)] + } + File excludedRootsFile = new File("$context.paths.temp/excluded.classpath") + excludedRootsFile.text = excludedRoots.findAll { new File(it).exists() }.join('\n') + additionalSystemProperties["exclude.tests.roots.file"] = excludedRootsFile.absolutePath + } + + runTestsProcess(mainModule, options.testGroups, options.testPatterns, additionalJvmOptions, additionalSystemProperties, false + ) + } + + private void debugTests(String remoteDebugJvmOptions, List additionalJvmOptions, String defaultMainModule, Predicate rootExcludeCondition) { + def testConfigurationType = System.getProperty("teamcity.remote-debug.type") + if (testConfigurationType != "junit") { + context.messages.error("Remote debugging is supported for junit run configurations only, but 'teamcity.remote-debug.type' is $testConfigurationType") + } + + def testObject = System.getProperty("teamcity.remote-debug.junit.type") + def junitClass = System.getProperty("teamcity.remote-debug.junit.class") + if (testObject != "class") { + context.messages.error("Remote debugging supports debugging all test methods in a class for now, debugging isn't supported for '$testObject'") + } + if (junitClass == null) { + context.messages.error("Remote debugging supports debugging all test methods in a class for now, but target class isn't specified") + } + if (options.testPatterns != null) { + context.messages.warning("'intellij.build.test.patterns' option is ignored while debugging via TeamCity plugin") + } + if (options.testConfigurations != null) { + context.messages.warning("'intellij.build.test.configurations' option is ignored while debugging via TeamCity plugin") + } + def mainModule = options.mainModule ?: defaultMainModule + def filteredOptions = removeStandardJvmOptions(remoteDebugJvmOptions.split(";").toList()) + runTestsProcess(mainModule, null, junitClass, filteredOptions + additionalJvmOptions, [:], true) + } + + private void runTestsProcess(String mainModule, String testGroups, String testPatterns, + List additionalJvmOptions, Map additionalSystemProperties, boolean remoteDebugging) { List testsClasspath = context.getModuleRuntimeClasspath(context.findRequiredModule(mainModule), true) List bootstrapClasspath = context.getModuleRuntimeClasspath(context.findRequiredModule("tests_bootstrap"), false) def classpathFile = new File("$context.paths.temp/junit.classpath") @@ -91,35 +199,14 @@ class TestingTasksImpl extends TestingTasks { String tempDir = System.getProperty("teamcity.build.tempDir", System.getProperty("java.io.tmpdir")) - def remoteDebugJvmOptions = System.getProperty("teamcity.remote-debug.jvm.options") - if (remoteDebugJvmOptions != null) { - def testConfigurationType = System.getProperty("teamcity.remote-debug.type") - if (testConfigurationType != "junit") { - context.messages.error("Remote debugging is supported for junit run configurations only, but 'teamcity.remote-debug.type' is $testConfigurationType") - } - - def testObject = System.getProperty("teamcity.remote-debug.junit.type") - def junitClass = System.getProperty("teamcity.remote-debug.junit.class") - if (testObject != "class") { - context.messages.error("Remote debugging supports debugging all test methods in a class for now, debugging isn't supported for '$testObject'") - } - if (junitClass == null) { - context.messages.error("Remote debugging supports debugging all test methods in a class for now, but target class isn't specified") - } - if (options.testPatterns != null) { - context.messages.warning("'intellij.build.test.patterns' option is ignored while debugging via TeamCity plugin") - } - options.testPatterns = junitClass - } - Map systemProperties = [ "classpath.file" : classpathFile.absolutePath, "idea.platform.prefix" : options.platformPrefix, "idea.home.path" : context.paths.projectHome, "idea.config.path" : "$tempDir/config".toString(), "idea.system.path" : "$tempDir/system".toString(), - "intellij.build.test.patterns" : options.testPatterns, - "intellij.build.test.groups" : options.testGroups, + "intellij.build.test.patterns" : testPatterns, + "intellij.build.test.groups" : testGroups, "idea.performance.tests" : System.getProperty("idea.performance.tests"), "idea.coverage.enabled.build" : System.getProperty("idea.coverage.enabled.build"), "teamcity.buildConfName" : System.getProperty("teamcity.buildConfName"), @@ -131,6 +218,7 @@ class TestingTasksImpl extends TestingTasks { "file.encoding" : "UTF-8", "io.netty.leakDetectionLevel" : "PARANOID", ] as Map + systemProperties.putAll(additionalSystemProperties) (System.getProperties() as Hashtable).each { String key, String value -> if (key.startsWith("pass.")) { @@ -138,33 +226,12 @@ class TestingTasksImpl extends TestingTasks { } } - if (rootExcludeCondition != null) { - List excludedModules = context.project.modules.findAll { - List contentRoots = it.contentRootsList.urls - !contentRoots.isEmpty() && rootExcludeCondition.test(JpsPathUtil.urlToFile(contentRoots.first())) - } - List excludedRoots = excludedModules.collectMany { - [context.getModuleOutputPath(it), context.getModuleTestsOutputPath(it)] - } - File excludedRootsFile = new File("$context.paths.temp/excluded.classpath") - excludedRootsFile.text = excludedRoots.findAll { new File(it).exists() }.join('\n') - systemProperties["exclude.tests.roots.file"] = excludedRootsFile.absolutePath - } - boolean suspendDebugProcess = options.suspendDebugProcess if (systemProperties["idea.performance.tests"] == "true") { context.messages.info("Debugging disabled for performance tests") suspendDebugProcess = false } - else if (remoteDebugJvmOptions != null) { - // ignore all options from the run configuration because they may conflict with the options defined in the build script - String jvmDebugOption = StringUtil.splitHonorQuotes(remoteDebugJvmOptions, ' ' as char).find { it.startsWith("-agentlib:jdwp=") } - if (jvmDebugOption == null) { - context.messages.error("Cannot extract JVM debugging options from $remoteDebugJvmOptions") - } - - jvmArgs.add(jvmDebugOption) - + else if (remoteDebugging) { context.messages.info("Remote debugging via TeamCity plugin is activated.") if (suspendDebugProcess) { context.messages.warning("'intellij.build.test.debug.suspend' option is ignored while debugging via TeamCity plugin") @@ -179,7 +246,7 @@ class TestingTasksImpl extends TestingTasks { jvmArgs.add(debuggerParameter) } - context.messages.info("Starting ${options.testGroups != null ? "test from groups '$options.testGroups'" : "all tests"}") + context.messages.info("Starting ${testGroups != null ? "test from groups '${testGroups}'" : "all tests"}") if (options.customJrePath != null) { context.messages.info("JVM: $options.customJrePath") } diff --git a/platform/build-scripts/tests/platform-build-scripts-tests.iml b/platform/build-scripts/tests/platform-build-scripts-tests.iml new file mode 100644 index 000000000000..ddb12af2d8c7 --- /dev/null +++ b/platform/build-scripts/tests/platform-build-scripts-tests.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_class.xml b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_class.xml new file mode 100644 index 000000000000..bd86250ae070 --- /dev/null +++ b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_class.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_package.xml b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_package.xml new file mode 100644 index 000000000000..59a633310af0 --- /dev/null +++ b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_package.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_pattern.xml b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_pattern.xml new file mode 100644 index 000000000000..c30153749057 --- /dev/null +++ b/platform/build-scripts/tests/testResources/org/jetbrains/intellij/build/runConfigurations/test_pattern.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/JUnitRunConfigurationPropertiesTest.kt b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/JUnitRunConfigurationPropertiesTest.kt new file mode 100644 index 000000000000..a9e9f5b9dc2e --- /dev/null +++ b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/JUnitRunConfigurationPropertiesTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ +package org.jetbrains.intellij.build + +import com.intellij.util.io.URLUtil +import org.jetbrains.intellij.build.impl.JUnitRunConfigurationProperties +import org.junit.Assert.assertEquals +import org.junit.Test + +class JUnitRunConfigurationPropertiesTest { + @Test + fun `load test class`() { + val properties = loadRunConfiguration("test_class.xml") + assertEquals("test class", properties.name) + assertEquals("main-module", properties.moduleName) + assertEquals(listOf("com.example.test.MainTest"), properties.testClassPatterns) + assertEquals(listOf("-ea", "-Xmx512m"), properties.vmParameters) + assertEquals(listOf("artifact1", "artifact2"), properties.requiredArtifacts) + } + + @Test + fun `load test package`() { + val properties = loadRunConfiguration("test_package.xml") + assertEquals("test package", properties.name) + assertEquals("main-module", properties.moduleName) + assertEquals(listOf("com.example.test.*"), properties.testClassPatterns) + assertEquals(listOf("-ea"), properties.vmParameters) + assertEquals(emptyList(), properties.requiredArtifacts) + } + + @Test + fun `load test pattern`() { + val properties = loadRunConfiguration("test_pattern.xml") + assertEquals("test pattern", properties.name) + assertEquals("main-module", properties.moduleName) + assertEquals(listOf("com.example.Test", "com.example.package..*"), properties.testClassPatterns) + assertEquals(listOf("-ea"), properties.vmParameters) + assertEquals(emptyList(), properties.requiredArtifacts) + } + + private fun loadRunConfiguration(fileName: String): JUnitRunConfigurationProperties { + val url = JUnitRunConfigurationPropertiesTest::class.java.getResource("runConfigurations/$fileName") + return JUnitRunConfigurationProperties.loadRunConfiguration(URLUtil.urlToFile(url), MockBuildMessages()) + } +} \ No newline at end of file diff --git a/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/MockBuildMessages.kt b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/MockBuildMessages.kt new file mode 100644 index 000000000000..5c8fc530a0fb --- /dev/null +++ b/platform/build-scripts/tests/testSrc/org/jetbrains/intellij/build/MockBuildMessages.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ +package org.jetbrains.intellij.build + +import groovy.lang.Closure +import junit.framework.AssertionFailedError + +class MockBuildMessages : BuildMessages { + override fun info(message: String?) { + } + + override fun warning(message: String?) { + } + + override fun error(message: String?) { + throw AssertionFailedError(message) + } + + override fun error(message: String?, cause: Throwable?) { + throw AssertionFailedError(message) + } + + override fun compilationError(compilerName: String?, message: String?) { + } + + override fun compilationErrors(compilerName: String?, messages: MutableList?) { + } + + override fun progress(message: String?) { + } + + override fun block(blockName: String, body: Closure): V { + return body.call() + } + + override fun artifactBuilt(relativeArtifactPath: String?) { + } + + override fun reportStatisticValue(key: String?, value: String?) { + } + + override fun forkForParallelTask(taskName: String?): BuildMessages { + throw UnsupportedOperationException() + } + + override fun onAllForksFinished() { + } + + override fun onForkStarted() { + } + + override fun onForkFinished() { + } +} \ No newline at end of file