diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
index f18d9f09a515..0483d9ff34c6 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenSessionBuilderSupplier.java
@@ -100,11 +100,13 @@ public DependencyManager getDependencyManager(boolean transitive) {
}
public DependencySelector getDependencySelector() {
+ DependencySelector scopeSelector = ScopeDependencySelector.legacy(
+ null, Arrays.asList(DependencyScope.TEST.id(), DependencyScope.PROVIDED.id()));
+ if (!mavenMaven3Personality) {
+ scopeSelector = new TestJarDependencySelector(scopeSelector);
+ }
return new AndDependencySelector(
- ScopeDependencySelector.legacy(
- null, Arrays.asList(DependencyScope.TEST.id(), DependencyScope.PROVIDED.id())),
- OptionalDependencySelector.fromDirect(),
- new ExclusionDependencySelector());
+ scopeSelector, OptionalDependencySelector.fromDirect(), new ExclusionDependencySelector());
}
public DependencyGraphTransformer getDependencyGraphTransformer() {
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java
new file mode 100644
index 000000000000..fa038992793d
--- /dev/null
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/TestJarDependencySelector.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.maven.impl.resolver;
+
+import java.util.Objects;
+
+import org.apache.maven.api.DependencyScope;
+import org.apache.maven.api.Type;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.collection.DependencyCollectionContext;
+import org.eclipse.aether.collection.DependencySelector;
+import org.eclipse.aether.graph.Dependency;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Preserves Maven's normal non-transitive test-scope semantics while allowing the direct test-scoped dependencies of
+ * a test JAR to participate in dependency collection. Those dependencies are part of the test artifact's classpath
+ * contract, not the producer's main artifact contract.
+ */
+final class TestJarDependencySelector implements DependencySelector {
+ private final DependencySelector delegate;
+ private final boolean testJarParent;
+
+ TestJarDependencySelector(DependencySelector delegate) {
+ this(delegate, false);
+ }
+
+ private TestJarDependencySelector(DependencySelector delegate, boolean testJarParent) {
+ this.delegate = requireNonNull(delegate, "delegate cannot be null");
+ this.testJarParent = testJarParent;
+ }
+
+ @Override
+ public boolean selectDependency(Dependency dependency) {
+ requireNonNull(dependency, "dependency cannot be null");
+ if (testJarParent && DependencyScope.TEST.id().equals(dependency.getScope())) {
+ return true;
+ }
+ return delegate.selectDependency(dependency);
+ }
+
+ @Override
+ public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
+ requireNonNull(context, "context cannot be null");
+
+ DependencySelector childDelegate = delegate.deriveChildSelector(context);
+ Dependency parent = context.getDependency();
+ boolean childOfTestJar = parent != null
+ && Type.TEST_JAR.equals(parent.getArtifact().getProperty(ArtifactProperties.TYPE, ""));
+
+ if (childDelegate == delegate && childOfTestJar == testJarParent) {
+ return this;
+ }
+ return new TestJarDependencySelector(childDelegate, childOfTestJar);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestJarDependencySelector that)) {
+ return false;
+ }
+ return testJarParent == that.testJarParent && delegate.equals(that.delegate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(delegate, testJarParent);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[delegate=" + delegate + ", testJarParent=" + testJarParent + ']';
+ }
+}
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java
new file mode 100644
index 000000000000..f30ba775a978
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng1378TestJarTransitiveDependenciesTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.maven.it;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Integration test for MNG-1378.
+ */
+public class MavenITmng1378TestJarTransitiveDependenciesTest extends AbstractMavenIntegrationTestCase {
+
+ @Test
+ public void testTestJarCarriesProducerTestDependencies() throws Exception {
+ Path testDir = extractResources("mng-1378");
+
+ Verifier producer = newVerifier(testDir);
+ producer.setAutoclean(false);
+ producer.deleteArtifacts("org.apache.maven.its.mng1378");
+ producer.addCliArgument("-pl");
+ producer.addCliArgument("support,test-jar");
+ producer.addCliArgument("validate");
+ producer.execute();
+ producer.verifyErrorFreeLog();
+
+ Verifier consumer = newVerifier(testDir.resolve("consumer"));
+ consumer.setAutoclean(false);
+ consumer.addCliArgument("validate");
+ consumer.execute();
+ consumer.verifyErrorFreeLog();
+
+ List testClasspath = consumer.loadLines("target/test.txt");
+ assertTrue(testClasspath.contains("test-jar-1.0-tests.jar"), testClasspath.toString());
+ assertTrue(testClasspath.contains("support-1.0.jar"), testClasspath.toString());
+
+ Verifier regularConsumer = newVerifier(testDir.resolve("regular-consumer"));
+ regularConsumer.setAutoclean(false);
+ regularConsumer.addCliArgument("validate");
+ regularConsumer.execute();
+ regularConsumer.verifyErrorFreeLog();
+
+ List regularTestClasspath = regularConsumer.loadLines("target/test.txt");
+ assertTrue(regularTestClasspath.contains("test-jar-1.0.jar"), regularTestClasspath.toString());
+ assertFalse(regularTestClasspath.contains("support-1.0.jar"), regularTestClasspath.toString());
+ }
+}
diff --git a/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml
new file mode 100644
index 000000000000..2e9b1c66dbcc
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-1378/consumer/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng1378
+ consumer
+ 1.0
+
+ Maven Integration Test :: MNG-1378 :: Test JAR Consumer
+
+
+
+ org.apache.maven.its.mng1378
+ test-jar
+ 1.0
+ test-jar
+ test
+
+
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-dependency-resolution
+ 2.1-SNAPSHOT
+
+
+ test
+
+ test
+
+ validate
+
+ target/test.txt
+ 1
+
+
+
+
+
+
+
diff --git a/its/core-it-suite/src/test/resources/mng-1378/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/pom.xml
new file mode 100644
index 000000000000..f73f76e221a2
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-1378/pom.xml
@@ -0,0 +1,37 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng1378
+ parent
+ 1.0
+ pom
+
+ Maven Integration Test :: MNG-1378
+ Verify that dependencies required by a producer's test JAR are transitively available to test-JAR consumers.
+
+
+ support
+ test-jar
+ consumer
+ regular-consumer
+
+
diff --git a/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml
new file mode 100644
index 000000000000..17bd00050f25
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-1378/regular-consumer/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng1378
+ regular-consumer
+ 1.0
+
+ Maven Integration Test :: MNG-1378 :: Regular JAR Consumer
+
+
+
+ org.apache.maven.its.mng1378
+ test-jar
+ 1.0
+ test
+
+
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-dependency-resolution
+ 2.1-SNAPSHOT
+
+
+ test
+
+ test
+
+ validate
+
+ target/test.txt
+ 1
+
+
+
+
+
+
+
diff --git a/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml
new file mode 100644
index 000000000000..c0d7f5ba0117
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-1378/support/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng1378
+ support
+ 1.0
+
+ Maven Integration Test :: MNG-1378 :: Test Support
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-artifact
+ 2.1-SNAPSHOT
+
+ pom.xml
+
+
+
+ install
+
+ set
+ install
+
+ validate
+
+
+
+
+
+
diff --git a/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml b/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml
new file mode 100644
index 000000000000..0294fd3bf9d2
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-1378/test-jar/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng1378
+ test-jar
+ 1.0
+
+ Maven Integration Test :: MNG-1378 :: Test JAR Producer
+
+
+
+ org.apache.maven.its.mng1378
+ support
+ 1.0
+ test
+
+
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-artifact
+ 2.1-SNAPSHOT
+
+
+ install
+
+ set
+ attach-pom
+ attach
+ install
+
+ validate
+
+ pom.xml
+ pom.xml
+ test-jar
+ tests
+
+
+
+
+
+
+