diff --git a/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml b/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml
new file mode 100644
index 000000000..8cb98da5f
--- /dev/null
+++ b/org.eclipse.m2e.jdt.tests/projects/surefireFailsafeToTestLaunchSettings/deferredVariables/pom.xml
@@ -0,0 +1,105 @@
+
+ 4.0.0
+ TMP
+ TMP
+ 0.0.1-SNAPSHOT
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.0
+
+
+ default-test
+ test
+
+ test
+
+
+
+
+ -Xshare:off
+ -Djdk.net.URLClassPath.disableClassPathURLCheck=true
+ @{jacoco.surefireArgLine} @{titi.tata}
+
+
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.12
+
+
+ coverage-prepare-agent
+
+ prepare-agent
+
+
+
+ jacoco.surefireArgLine
+
+
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ [0.0.0,)
+
+ prepare-agent
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.junit
+ junit-bom
+ 5.11.0
+ pom
+ import
+
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
\ No newline at end of file
diff --git a/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java
index e3f24fcc8..3d98a8f20 100644
--- a/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java
+++ b/org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/UnitTestLaunchConfigConfigurationTest.java
@@ -56,26 +56,30 @@ public class UnitTestLaunchConfigConfigurationTest extends AbstractMavenProjectT
private static final String SUREFIRE_ARGS_SET = """
- --argLineItem=surefireArgLineValue
+ --argLineItem=surefireArgLineValue --undefinedArgLineItem=${undefinedProperty}
surefireProp1Value
+ ${undefinedProperty}
surefireEnvironmentVariables1Value
+ ${undefinedProperty}
""";
private static final String FAILSAFE_ARGS_SET = """
- --argLineItem=failsafeArgLineValue
+ --argLineItem=failsafeArgLineValue --undefinedArgLineItem=${undefinedProperty}
failsafeProp1Value
+ ${undefiniedProperty}
failsafeEnvironmentVariables1Value
+ ${undefinedProperty}
""";
@@ -144,6 +148,10 @@ public void test_configuration_must_be_updated_with_surefire_config()
// check systemPropertyVariables
assertTrue(argLine.contains("-DsurefireProp1=surefireProp1Value"));
+
+ // check systemPropertyVariables with null value aren't set
+ assertTrue(!argLine.contains("-DsurefireEmptyProp="));
+
}
@Test
@@ -193,6 +201,9 @@ public void test_configuration_must_be_updated_with_failsafe_config()
// check systemPropertyVariables
assertTrue(argLine.contains("-DfailsafeProp1=failsafeProp1Value"));
+
+ // check systemPropertyVariables with null value aren't set
+ assertTrue(!argLine.contains("-DfailsafeEmptyProp="));
}
@Test
@@ -279,6 +290,32 @@ public void test_configuration_must_be_updated_with_failSafe_config_when_created
assertTrue(argLine.contains("-DfailsafeProp1=failsafeProp1Value"));
}
+ @Test
+ public void test_deferred_variable_are_resolved() throws CoreException, IOException, InterruptedException {
+ // Get launch type
+ ILaunchConfigurationType type = LAUNCH_MANAGER.getLaunchConfigurationType(testType);
+
+ assumeTrue(testType + " support not available", type != null);
+
+ File pomFile = getTestFile("deferredVariables/pom.xml");
+
+ IProject project = importProject(pomFile.getAbsolutePath());
+
+ // create basic unit test
+ createDefaultTest(project, type, "test.SomeTest");
+
+ updateProject(project);
+ waitForJobsToComplete();
+
+ ILaunchConfiguration[] updatedConfigurations = LAUNCH_MANAGER.getLaunchConfigurations(type);
+ assertTrue(updatedConfigurations.length == 1);
+
+ ILaunchConfiguration config = updatedConfigurations[0];
+ String argLine = config.getAttribute(UnitTestSupport.LAUNCH_CONFIG_VM_ARGUMENTS, "");
+ assertTrue(argLine.contains("-javaagent")); // resolved jacoco agent
+ assertTrue(argLine.contains("@{titi.tata}")); // unresolved property is unchanged as in CLI
+ }
+
private void updateProject(IProject project) throws CoreException, InterruptedException {
MavenPlugin.getProjectConfigurationManager().updateProjectConfiguration(project, monitor);
waitForJobsToComplete();
diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java
index e57f9e737..7b21dac9a 100644
--- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java
+++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/UnitTestSupport.java
@@ -24,8 +24,11 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Properties;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -143,6 +146,11 @@ public class UnitTestSupport {
*/
private static final String FAILSAFE_PLUGIN_ARTIFACT_ID = "maven-failsafe-plugin";
+ /**
+ * deffered variable pattern
+ */
+ private static final Pattern DEFERRED_VAR_PATTERN = Pattern.compile("@\\{(.*?)\\}");
+
/**
* maven group id for the maven plugins
*/
@@ -271,7 +279,9 @@ private void defineConfigurationValues(IProject project, ILaunchConfiguration co
launchArguments.add(args.argLine());
}
if(args.systemPropertyVariables() != null) {
- args.systemPropertyVariables().forEach((key, value) -> launchArguments.add("-D" + key + "=" + value));
+ args.systemPropertyVariables().entrySet().stream() //
+ .filter(e -> e.getKey() != null && e.getValue() != null)
+ .forEach(e -> launchArguments.add("-D" + e.getKey() + "=" + e.getValue()));
}
copy.setAttribute(LAUNCH_CONFIG_VM_ARGUMENTS, launchArguments.toString());
@@ -287,7 +297,10 @@ private void defineConfigurationValues(IProject project, ILaunchConfiguration co
}
if(args.environmentVariables() != null) {
- copy.setAttribute(LAUNCH_CONFIG_ENVIRONMENT_VARIABLES, args.environmentVariables());
+ Map filteredMap = args.environmentVariables().entrySet().stream()
+ .filter(entry -> entry.getKey() != null && entry.getValue() != null)
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ copy.setAttribute(LAUNCH_CONFIG_ENVIRONMENT_VARIABLES, filteredMap);
}
copy.doSave();
@@ -398,8 +411,11 @@ private TestLaunchArguments getTestLaunchArguments(MavenProject mavenProject, Mo
IProgressMonitor monitor) {
try {
IMaven maven = MavenPlugin.getMaven();
- return new TestLaunchArguments(
- maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ARGLINE, String.class, monitor),
+
+ String argLine = maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ARGLINE, String.class, monitor);
+ argLine = resolveDeferredVariables(mavenProject, argLine);
+
+ return new TestLaunchArguments(argLine,
maven.getMojoParameterValue(mavenProject, execution, PLUGIN_SYSPROP_VARIABLES, Map.class, monitor),
maven.getMojoParameterValue(mavenProject, execution, PLUGIN_ENVIRONMENT_VARIABLES, Map.class, monitor),
maven.getMojoParameterValue(mavenProject, execution, PLUGIN_WORKING_DIRECTORY, File.class, monitor),
@@ -412,6 +428,29 @@ private TestLaunchArguments getTestLaunchArguments(MavenProject mavenProject, Mo
}
+ /**
+ * This method is used to resolve deferred variables introduced by failsafe/surefire plugins in a given string value.
+ * Deferred variables are placeholders in the string that are replaced with actual values from the Maven project's
+ * properties. The placeholders are in the format @{...}, where ... is the key of the property. If a placeholder's
+ * corresponding property does not exist, the placeholder is left as is.
+ *
+ * @param mavenProject the Maven project from which to retrieve the properties
+ * @param value the string containing the placeholders to be replaced
+ * @return the string with all resolvable placeholders replaced with their corresponding property values
+ */
+ private static String resolveDeferredVariables(MavenProject mavenProject, String value) {
+ Properties properties = mavenProject.getProperties();
+ if(properties.isEmpty() || value == null) {
+ return value;
+ }
+ return DEFERRED_VAR_PATTERN.matcher(value).replaceAll(match -> {
+ String placeholder = match.group();
+ String key = match.group(1);
+ String replacement = properties.getProperty(key);
+ return replacement != null ? replacement : placeholder;
+ });
+ }
+
/**
* Holder for the surefire/failsafe launch arguments
*/