jarNames(GroovyClassLoader loader) {
+ loader.URLs.collect { url -> url.path.split('/')[-1] } as Set
+ }
+
+ @Test
+ void testResolveReturnsUris() {
+ URI[] uris = Grape.resolve([autoDownload: true, classLoader: new GroovyClassLoader()],
+ [groupId: 'commons-logging', artifactId: 'commons-logging', version: '1.2'])
+
+ assert uris.length > 0
+ assert uris.any { it.toString().contains('commons-logging-1.2') }
+ }
+
+ @Test
+ void testListDependenciesAfterGrab() {
+ def loader = new GroovyClassLoader()
+
+ Grape.grab(classLoader: loader,
+ [groupId: 'commons-logging', artifactId: 'commons-logging', version: '1.2'])
+
+ Map[] loadedDependencies = Grape.listDependencies(loader)
+ assert loadedDependencies.find {
+ it.group == 'commons-logging' && it.module == 'commons-logging' && it.version == '1.2'
+ }
+ }
+
+ @Test
+ void testNonTransitiveGrabResolvesOnlyDirectArtifact() {
+ URI[] uris = Grape.resolve([autoDownload: true, classLoader: new GroovyClassLoader()],
+ [groupId: 'org.apache.httpcomponents', artifactId: 'httpclient', version: '4.5.14', transitive: false])
+
+ assert uris.any { it.toString().contains('httpclient-4.5.14') }
+ assert !uris.any { it.toString().contains('httpcore-') }
+ }
+
+ @Test
+ void testClassifierResolvesJsonLibJdk15() {
+ def loader = new GroovyClassLoader()
+
+ Grape.grab(classLoader: loader,
+ [groupId: 'net.sf.json-lib', artifactId: 'json-lib', version: '2.2.3', classifier: 'jdk15'])
+
+ Set jars = jarNames(loader)
+ assert jars.any { it == 'json-lib-2.2.3-jdk15.jar' }
+ assert jars.any { it.startsWith('ezmorph-') }
+ }
+
+ @Test
+ void testOptionalDependencyIsNotPulledTransitively() {
+ File tempRoot = Files.createTempDirectory('grape-maven-optional-test').toFile()
+ File repoDir = new File(tempRoot, 'repo')
+
+ String g = 'dev.grape.optional'
+ deleteCachedGroup(g)
+ publishArtifact(repoDir, g, 'dep-required', '1.0.0')
+ publishArtifact(repoDir, g, 'dep-optional', '1.0.0')
+ publishArtifact(repoDir, g, 'root-artifact', '1.0.0', [
+ [groupId: g, artifactId: 'dep-required', version: '1.0.0', optional: false],
+ [groupId: g, artifactId: 'dep-optional', version: '1.0.0', optional: true],
+ ])
+
+ Grape.addResolver(name: 'local-optional-test', root: repoDir.toURI().toString(), m2Compatible: true)
+ URI[] uris = Grape.resolve([autoDownload: true, classLoader: new GroovyClassLoader()],
+ [groupId: g, artifactId: 'root-artifact', version: '1.0.0'])
+
+ assert uris.any { it.toString().contains('root-artifact-1.0.0.jar') }
+ assert uris.any { it.toString().contains('dep-required-1.0.0.jar') }
+ assert !uris.any { it.toString().contains('dep-optional-1.0.0.jar') }
+ }
+}
diff --git a/subprojects/groovy-grape-test/build.gradle b/subprojects/groovy-grape-test/build.gradle
new file mode 100644
index 00000000000..05de679608b
--- /dev/null
+++ b/subprojects/groovy-grape-test/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+plugins {
+ id 'groovy'
+ id 'org.apache.groovy-common'
+ id 'org.apache.groovy-internal'
+ id 'org.apache.groovy-tested'
+}
+
+dependencies {
+ testImplementation rootProject
+ testImplementation projects.groovyTest
+ testImplementation projects.groovyTestJunit5
+ testRuntimeOnly projects.groovyGrapeIvy
+ testRuntimeOnly projects.groovyGrapeMaven
+}
+
+tasks.named('test', Test) {
+ useJUnitPlatform()
+ forkEvery = 1
+ maxParallelForks = 1
+}
+
diff --git a/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeConfiguredMavenSelectionTest.groovy b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeConfiguredMavenSelectionTest.groovy
new file mode 100644
index 00000000000..1797444bcf2
--- /dev/null
+++ b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeConfiguredMavenSelectionTest.groovy
@@ -0,0 +1,37 @@
+/*
+ * 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 groovy.grape
+
+import org.junit.jupiter.api.Test
+
+final class GrapeConfiguredMavenSelectionTest {
+ @Test
+ void testConfiguredMavenImplementationIgnoresIvyProvider() {
+ System.setProperty('groovy.grape.impl', 'groovy.grape.maven.GrapeMaven')
+ String output = GrapeSelectionTestSupport.captureStderr {
+ assert Grape.instance != null
+ }
+
+ assert output.contains("ignoring provider 'groovy.grape.ivy.GrapeIvy'")
+ assert output.contains("'groovy.grape.maven.GrapeMaven' configured via -Dgroovy.grape.impl")
+ }
+}
+
+
+
diff --git a/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeDefaultProviderSelectionTest.groovy b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeDefaultProviderSelectionTest.groovy
new file mode 100644
index 00000000000..ce5514d1ea1
--- /dev/null
+++ b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeDefaultProviderSelectionTest.groovy
@@ -0,0 +1,34 @@
+/*
+ * 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 groovy.grape
+
+import org.junit.jupiter.api.Test
+
+final class GrapeDefaultProviderSelectionTest {
+ @Test
+ void testNoConfiguredImplementationUsesDefaultAndLogsIgnoredProvider() {
+ String output = GrapeSelectionTestSupport.captureStderr {
+ assert Grape.instance != null
+ }
+
+ assert output.contains("ignoring provider 'groovy.grape.maven.GrapeMaven'")
+ assert output.contains("in favour of default 'groovy.grape.ivy.GrapeIvy'")
+ }
+}
+
diff --git a/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeImplementationSelectionTest.groovy b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeImplementationSelectionTest.groovy
new file mode 100644
index 00000000000..99b36f05a12
--- /dev/null
+++ b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeImplementationSelectionTest.groovy
@@ -0,0 +1,36 @@
+/*
+ * 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 groovy.grape
+
+import org.junit.jupiter.api.Test
+
+final class GrapeImplementationSelectionTest {
+ @Test
+ void testConfiguredImplementationMismatchSkipsServiceLoad() {
+ // This module runs with both implementations available; selecting an implementation
+ // that is not on this test runtime classpath should disable Grapes.
+ System.setProperty('groovy.grape.impl', 'groovy.grape.nonexistent.DoesNotExist')
+ String output = GrapeSelectionTestSupport.captureStderr {
+ assert Grape.instance == null
+ }
+
+ assert output.contains("configured implementation 'groovy.grape.nonexistent.DoesNotExist' not found")
+ assert output.contains('Grapes disabled')
+ }
+}
diff --git a/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeSelectionTestSupport.groovy b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeSelectionTestSupport.groovy
new file mode 100644
index 00000000000..d7e6ce0821e
--- /dev/null
+++ b/subprojects/groovy-grape-test/src/test/groovy/groovy/grape/GrapeSelectionTestSupport.groovy
@@ -0,0 +1,36 @@
+/*
+ * 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 groovy.grape
+
+final class GrapeSelectionTestSupport {
+ private GrapeSelectionTestSupport() {
+ }
+
+ static String captureStderr(Closure> action) {
+ def originalErr = System.err
+ def errBytes = new ByteArrayOutputStream()
+ try {
+ System.setErr(new PrintStream(errBytes, true, 'UTF-8'))
+ action.call()
+ return errBytes.toString('UTF-8')
+ } finally {
+ System.setErr(originalErr)
+ }
+ }
+}
diff --git a/subprojects/groovy-jmx/build.gradle b/subprojects/groovy-jmx/build.gradle
index 036d27296ca..67d220ae568 100644
--- a/subprojects/groovy-jmx/build.gradle
+++ b/subprojects/groovy-jmx/build.gradle
@@ -29,5 +29,6 @@ dependencies {
requireCapability 'org.apache.groovy:groovy-grapes'
}
}
+ testRuntimeOnly projects.groovyGrapeIvy
testRuntimeOnly projects.groovySwing
}
diff --git a/subprojects/groovy-json/build.gradle b/subprojects/groovy-json/build.gradle
index 4630a335002..15ac68ccab0 100644
--- a/subprojects/groovy-json/build.gradle
+++ b/subprojects/groovy-json/build.gradle
@@ -33,6 +33,7 @@ dependencies {
requireCapability 'org.apache.groovy:groovy-grapes'
}
}
+ testRuntimeOnly projects.groovyGrapeIvy
testRuntimeOnly projects.groovyAnt // for JavadocAssertionTests
testRuntimeOnly 'com.google.code.gson:gson:2.13.2' // json-unit requires gson, jackson1 or jackson2
}
diff --git a/subprojects/groovy-sql/build.gradle b/subprojects/groovy-sql/build.gradle
index 116128481db..c393a07efa3 100644
--- a/subprojects/groovy-sql/build.gradle
+++ b/subprojects/groovy-sql/build.gradle
@@ -33,6 +33,7 @@ dependencies {
requireCapability("org.apache.groovy:groovy-grapes")
}
}
+ testRuntimeOnly projects.groovyGrapeIvy
testCompileOnly(projects.groovyMacro) {
because "tests are using macro methods"
}
diff --git a/subprojects/groovy-xml/build.gradle b/subprojects/groovy-xml/build.gradle
index 2869f9f6668..b7a96b8a5b2 100644
--- a/subprojects/groovy-xml/build.gradle
+++ b/subprojects/groovy-xml/build.gradle
@@ -36,6 +36,7 @@ dependencies {
requireCapability 'org.apache.groovy:groovy-grapes'
}
}
+ testRuntimeOnly projects.groovyGrapeIvy
}
plugins.withId('eclipse') {
diff --git a/subprojects/groovy-xml/src/main/groovy/groovy/xml/StaxBuilder.groovy b/subprojects/groovy-xml/src/main/groovy/groovy/xml/StaxBuilder.groovy
index 957ad455489..05d92d58cd4 100644
--- a/subprojects/groovy-xml/src/main/groovy/groovy/xml/StaxBuilder.groovy
+++ b/subprojects/groovy-xml/src/main/groovy/groovy/xml/StaxBuilder.groovy
@@ -31,7 +31,10 @@ package groovy.xml
* elem2('hello2')
* elem3(x:7)
* }
- * assert writer.toString() == 'hello1hello2'
+ * def pretty= writer.toString()
+ * .replaceAll(/<\?xml[^>]*>/, '') // remove XML declaration
+ * assert pretty in ['hello1hello2',
+ * 'hello1hello2']
*
* Or an external library such as Jettison can be used as follows:
*
diff --git a/subprojects/groovy-xml/src/spec/test/StaxBuilderTest.groovy b/subprojects/groovy-xml/src/spec/test/StaxBuilderTest.groovy
index 35e3f0d969a..2c8968415b8 100644
--- a/subprojects/groovy-xml/src/spec/test/StaxBuilderTest.groovy
+++ b/subprojects/groovy-xml/src/spec/test/StaxBuilderTest.groovy
@@ -32,7 +32,9 @@ class StaxBuilderTest extends GroovyTestCase {
elem2('world')
}
- assert writer.toString() == 'helloworld'
+ def pretty= writer.toString()
+ .replaceAll(/<\?xml[^>]*>/, '') // remove XML declaration
+ assert pretty == 'helloworld'
// end::stax_builder[]
}
@@ -56,4 +58,4 @@ class StaxBuilderTest extends GroovyTestCase {
// end::stax_builder_external_library[]
'''
}
-}
\ No newline at end of file
+}
diff --git a/versions.properties b/versions.properties
index dcc2277ac8d..c979e2a1a16 100644
--- a/versions.properties
+++ b/versions.properties
@@ -29,7 +29,7 @@ commonsCli=1.11.0
commonsMath3=3.6.1
gpars=1.2.1
ivy=2.5.3
-jackson=2.21.0
+jackson=2.21.1
jacksonAnnotations=2.21
jakartaServerPagesApi=3.1.1
jakartaServletApi=6.0.0
@@ -48,6 +48,8 @@ junit5Platform=1.14.3
log4j=1.2.17
log4j2=2.25.3
logback=1.5.27
+mavenResolverProvider=4.0.0-rc-5
+mavenResolverSupplier=2.0.16
openbeans=1.0.2
picocli=4.7.7
qdox=2.2.0