This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push: new a381970609 [MNG-7969][MNG-7981] Add missing information on Maven 4 version api to fix an exception (#1355) a381970609 is described below commit a3819706093b69a8cf07c8a01ceaddfb6bb1c0b7 Author: Tamas Cservenak <ta...@cservenak.net> AuthorDate: Tue Dec 19 20:08:55 2023 +0100 [MNG-7969][MNG-7981] Add missing information on Maven 4 version api to fix an exception (#1355) Co-authored-by: Guillaume Nodet <gno...@gmail.com> --- .../org/apache/maven/api/ArtifactCoordinate.java | 2 +- .../main/java/org/apache/maven/api/Session.java | 11 + .../main/java/org/apache/maven/api/Version.java | 3 - .../{VersionRange.java => VersionConstraint.java} | 26 +- .../java/org/apache/maven/api/VersionRange.java | 31 +- .../apache/maven/api/services/VersionParser.java | 11 + .../maven/internal/impl/AbstractSession.java | 5 + .../internal/impl/DefaultArtifactCoordinate.java | 6 +- .../internal/impl/DefaultDependencyCoordinate.java | 10 +- .../internal/impl/DefaultDependencyResolver.java | 11 +- .../apache/maven/internal/impl/DefaultProject.java | 13 +- .../maven/internal/impl/DefaultVersionParser.java | 11 +- .../impl/DefaultConsumerPomBuilder.java | 4 +- .../org/apache/maven/internal/impl/TestApi.java | 65 ++- .../1.0.3/commons-logging-1.0.3.jar | Bin .../1.0.3/commons-logging-1.0.3.jar.sha1 | 0 .../1.0.3/commons-logging-1.0.3.pom | 0 .../1.0.3/commons-logging-1.0.3.pom.sha1 | 0 ...logging-1.0.4-javadoc-resources.jar.lastUpdated | 0 .../1.0.4/commons-logging-1.0.4.jar | Bin .../1.0.4/commons-logging-1.0.4.jar.sha1 | 0 .../1.0.4/commons-logging-1.0.4.pom | 0 .../1.0.4/commons-logging-1.0.4.pom.sha1 | 0 .../apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar | Bin 0 -> 382708 bytes .../junit/junit/4.13.1/junit-4.13.1.jar.sha1 | 1 + .../apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom | 587 +++++++++++++++++++++ .../junit/junit/4.13.1/junit-4.13.1.pom.sha1 | 1 + .../maven/model/building/DefaultModelBuilder.java | 6 +- .../model/building/DefaultModelBuilderFactory.java | 16 +- ...{VersionParser.java => ModelVersionParser.java} | 13 +- .../internal/DefaultModelVersionParser.java | 146 ++++- .../repository/internal/AbstractVersionTest.java | 67 +++ .../internal/ModelVersionParserTest.java | 101 ++++ .../repository/internal/VersionRangeTest.java | 142 +++++ .../maven/repository/internal/VersionTest.java | 453 ++++++++++++++++ 35 files changed, 1687 insertions(+), 55 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java index 553e60fad3..7eb96410b7 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java @@ -62,7 +62,7 @@ public interface ArtifactCoordinate { * @return the version */ @Nonnull - VersionRange getVersion(); + VersionConstraint getVersion(); /** * The extension of the artifact. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index b7f6098868..a643ab9e8b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -463,4 +463,15 @@ public interface Session { */ @Nonnull VersionRange parseVersionRange(@Nonnull String versionRange); + + /** + * Parses the specified version constraint specification, for example "1.0" or "[1.0,2.0)". + * <p> + * Shortcut for {@code getService(VersionParser.class).parseVersionConstraint(...)}. + * + * @see org.apache.maven.api.services.VersionParser#parseVersionConstraint(String) + * @throws org.apache.maven.api.services.VersionParserException if the parsing failed + */ + @Nonnull + VersionConstraint parseVersionConstraint(@Nonnull String versionConstraint); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java index 367385fa38..ee29cc2b7e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java @@ -30,9 +30,6 @@ import org.apache.maven.api.annotations.Nonnull; */ @Experimental public interface Version extends Comparable<Version> { - - // TODO: add access to the version information - /** * Returns a string representation of this version. * @return the string representation of this version diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionConstraint.java similarity index 60% copy from api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java copy to api/maven-api-core/src/main/java/org/apache/maven/api/VersionConstraint.java index 375ac5f9f9..00633c186b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionConstraint.java @@ -20,19 +20,33 @@ package org.apache.maven.api; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; /** - * A range of versions. + * Version constraint for dependency. Constraint is either a range ("[1,2)") or recommended version ("1.0"). * * @since 4.0.0 */ @Experimental -public interface VersionRange { +public interface VersionConstraint { + /** + * Returns the range of this constraint, or {@code null} if none. + * <p> + * Note: only one, this method or {@link #getRecommendedVersion()} method must return non-{@code null} value. + */ + @Nullable + VersionRange getVersionRange(); - // TODO: v4: add access to the version information + /** + * Returns the recommended version of this constraint, or {@code null} if none. + * <p> + * Note: only one, this method or {@link #getVersionRange()} method must return non-{@code null} value. + */ + @Nullable + Version getRecommendedVersion(); /** - * Determines whether the specified version is contained within this range. + * Determines whether the specified version is contained within this constraint. * * @param version the version to test, must not be {@code null} * @return {@code true} if this range contains the specified version, {@code false} otherwise @@ -40,8 +54,8 @@ public interface VersionRange { boolean contains(@Nonnull Version version); /** - * Returns a string representation of this version range - * @return the string representation of this version range + * Returns a string representation of this version constraint + * @return the string representation of this version constraint */ @Nonnull String asString(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java index 375ac5f9f9..6f9ff4427b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java @@ -20,6 +20,7 @@ package org.apache.maven.api; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; /** * A range of versions. @@ -28,9 +29,6 @@ import org.apache.maven.api.annotations.Nonnull; */ @Experimental public interface VersionRange { - - // TODO: v4: add access to the version information - /** * Determines whether the specified version is contained within this range. * @@ -39,10 +37,37 @@ public interface VersionRange { */ boolean contains(@Nonnull Version version); + /** + * Returns the upper boundary of this range, or {@code null} if none. + */ + @Nullable + Boundary getUpperBoundary(); + + /** + * Returns the lower boundary of this range, or {@code null} if none. + */ + @Nullable + Boundary getLowerBoundary(); + /** * Returns a string representation of this version range * @return the string representation of this version range */ @Nonnull String asString(); + + /** + * Represents range boundary. + */ + interface Boundary { + /** + * The bounding version. + */ + Version getVersion(); + + /** + * Returns {@code true} if version is included of the range. + */ + boolean isInclusive(); + } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java index 1e9b591392..d344122d7f 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java @@ -20,6 +20,7 @@ package org.apache.maven.api.services; import org.apache.maven.api.Service; import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -53,6 +54,16 @@ public interface VersionParser extends Service { @Nonnull VersionRange parseVersionRange(@Nonnull String range); + /** + * Parses the specified version constraint specification, for example "1.0" or "[1.0,2.0)". + * + * @param constraint the constraint specification to parse, must not be {@code null} + * @return the parsed version constraint, never {@code null} + * @throws VersionParserException if the range specification violates the syntax rules of this scheme + */ + @Nonnull + VersionConstraint parseVersionConstraint(@Nonnull String constraint); + /** * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not. */ diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 0ef8cdf384..ce90e19be7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -504,6 +504,11 @@ public abstract class AbstractSession implements InternalSession { return getService(VersionParser.class).parseVersionRange(versionRange); } + @Override + public VersionConstraint parseVersionConstraint(String versionConstraint) { + return getService(VersionParser.class).parseVersionConstraint(versionConstraint); + } + @Override public Version resolveVersion(ArtifactCoordinate artifact) { return getService(VersionResolver.class).resolve(this, artifact).getVersion(); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java index 0dffe01927..04b4c73e28 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java @@ -21,7 +21,7 @@ package org.apache.maven.internal.impl; import java.util.Objects; import org.apache.maven.api.ArtifactCoordinate; -import org.apache.maven.api.VersionRange; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.annotations.Nonnull; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -57,8 +57,8 @@ public class DefaultArtifactCoordinate implements ArtifactCoordinate { @Nonnull @Override - public VersionRange getVersion() { - return session.parseVersionRange(coordinate.getVersion()); + public VersionConstraint getVersion() { + return session.parseVersionConstraint(coordinate.getVersion()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java index 64c2939e98..54121e8da6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java @@ -20,11 +20,7 @@ package org.apache.maven.internal.impl; import java.util.Collection; -import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.Exclusion; -import org.apache.maven.api.Scope; -import org.apache.maven.api.Type; -import org.apache.maven.api.VersionRange; +import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.services.TypeRegistry; @@ -63,8 +59,8 @@ public class DefaultDependencyCoordinate implements DependencyCoordinate { } @Override - public VersionRange getVersion() { - return session.parseVersionRange(dependency.getArtifact().getVersion()); + public VersionConstraint getVersion() { + return session.parseVersionConstraint(dependency.getArtifact().getVersion()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index 56f3c5bd53..c5ba1a32b0 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -112,8 +112,15 @@ public class DefaultDependencyResolver implements DependencyResolver { List<ArtifactCoordinate> coordinates = deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList()); Map<Artifact, Path> artifacts = session.resolveArtifacts(coordinates); - Map<Dependency, Path> dependencies = deps.stream().collect(Collectors.toMap(d -> d, artifacts::get)); - List<Path> paths = new ArrayList<>(dependencies.values()); + Map<Dependency, Path> dependencies = new LinkedHashMap<>(); + List<Path> paths = new ArrayList<>(); + for (Dependency d : deps) { + Path path = artifacts.get(d); + if (dependencies.put(d, path) != null) { + throw new IllegalStateException("Duplicate key"); + } + paths.add(path); + } return new DefaultDependencyResolverResult( collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index c92b060f4b..7b3ae6c198 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -26,14 +26,7 @@ import java.util.List; import java.util.Optional; import org.apache.maven.RepositoryUtils; -import org.apache.maven.api.Artifact; -import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.Exclusion; -import org.apache.maven.api.Project; -import org.apache.maven.api.RemoteRepository; -import org.apache.maven.api.Scope; -import org.apache.maven.api.Type; -import org.apache.maven.api.VersionRange; +import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.DependencyManagement; @@ -180,8 +173,8 @@ public class DefaultProject implements Project { } @Override - public VersionRange getVersion() { - return session.parseVersionRange(dependency.getVersion()); + public VersionConstraint getVersion() { + return session.parseVersionConstraint(dependency.getVersion()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java index 5cc2b106a4..780b9846d6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java @@ -25,8 +25,10 @@ import javax.inject.Singleton; import java.util.regex.Pattern; import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; import org.apache.maven.api.services.VersionParser; +import org.apache.maven.model.version.ModelVersionParser; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -39,10 +41,10 @@ public class DefaultVersionParser implements VersionParser { private static final String SNAPSHOT = "SNAPSHOT"; private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile("^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$"); - private final org.apache.maven.model.version.VersionParser modelVersionParser; + private final ModelVersionParser modelVersionParser; @Inject - public DefaultVersionParser(org.apache.maven.model.version.VersionParser modelVersionParser) { + public DefaultVersionParser(ModelVersionParser modelVersionParser) { this.modelVersionParser = nonNull(modelVersionParser, "modelVersionParser"); } @@ -56,6 +58,11 @@ public class DefaultVersionParser implements VersionParser { return modelVersionParser.parseVersionRange(range); } + @Override + public VersionConstraint parseVersionConstraint(String constraint) { + return modelVersionParser.parseVersionConstraint(constraint); + } + @Override public boolean isSnapshot(String version) { return checkSnapshot(version); diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 5878edf7a2..79f2cb7363 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -63,7 +63,7 @@ import org.apache.maven.model.profile.ProfileSelector; import org.apache.maven.model.superpom.SuperPomProvider; import org.apache.maven.model.v4.MavenModelVersion; import org.apache.maven.model.validation.ModelValidator; -import org.apache.maven.model.version.VersionParser; +import org.apache.maven.model.version.ModelVersionParser; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectModelResolver; @@ -128,7 +128,7 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { private SuperPomProvider superPomProvider; @Inject - private VersionParser versionParser; + private ModelVersionParser versionParser; // To break circular dependency @Inject diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java index af6fdc8bb4..f4ce6b1b1b 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java @@ -21,15 +21,23 @@ package org.apache.maven.internal.impl; import javax.inject.Inject; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.maven.api.Artifact; import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.Dependency; import org.apache.maven.api.Node; import org.apache.maven.api.Project; +import org.apache.maven.api.ResolutionScope; import org.apache.maven.api.Session; +import org.apache.maven.api.services.DependencyResolver; +import org.apache.maven.api.services.DependencyResolverResult; import org.apache.maven.api.services.ProjectBuilder; import org.apache.maven.api.services.ProjectBuilderRequest; import org.apache.maven.api.services.SettingsBuilder; @@ -120,7 +128,7 @@ class TestApi { } @Test - void testCreateAndResolveArtifact() throws Exception { + void testCreateAndResolveArtifact() { ArtifactCoordinate coord = session.createArtifactCoordinate("org.codehaus.plexus", "plexus-utils", "1.4.5", "pom"); @@ -131,21 +139,74 @@ class TestApi { Optional<Path> op = session.getArtifactPath(resolved.getKey()); assertTrue(op.isPresent()); assertEquals(resolved.getValue(), op.get()); + } + + @Test + void testBuildProject() { + Artifact artifact = session.createArtifact("org.codehaus.plexus", "plexus-utils", "1.4.5", "pom"); Project project = session.getService(ProjectBuilder.class) .build(ProjectBuilderRequest.builder() .session(session) - .path(op.get()) + .path(session.getPathForLocalArtifact(artifact)) .processPlugins(false) .resolveDependencies(false) .build()) .getProject() .get(); assertNotNull(project); + } + @Test + void testCollectArtifactDependencies() { Artifact artifact = session.createArtifact("org.codehaus.plexus", "plexus-container-default", "1.0-alpha-32", "jar"); Node root = session.collectDependencies(artifact); assertNotNull(root); } + + @Test + void testResolveArtifactCoordinateDependencies() { + ArtifactCoordinate coord = + session.createArtifactCoordinate("org.apache.maven.core.test", "test-extension", "1", "jar"); + + List<Path> paths = session.resolveDependencies(session.createDependencyCoordinate(coord)); + + assertNotNull(paths); + assertEquals(10, paths.size()); + assertTrue(paths.get(0).getFileName().toString().equals("test-extension-1.jar")); + } + + @Test + void testProjectDependencies() { + Artifact pom = session.createArtifact("org.codehaus.plexus", "plexus-container-default", "1.0-alpha-32", "pom"); + + Project project = session.getService(ProjectBuilder.class) + .build(ProjectBuilderRequest.builder() + .session(session) + .path(session.getPathForLocalArtifact(pom)) + .processPlugins(false) + .resolveDependencies(false) + .build()) + .getProject() + .get(); + assertNotNull(project); + + Artifact artifact = session.createArtifact("org.apache.maven.core.test", "test-extension", "1", "jar"); + Node root = session.collectDependencies(artifact); + assertNotNull(root); + + DependencyResolverResult result = + session.getService(DependencyResolver.class).resolve(session, project, ResolutionScope.PROJECT_RUNTIME); + assertNotNull(result); + List<Dependency> deps = new ArrayList<>(result.getDependencies().keySet()); + List<Dependency> deps2 = result.getNodes().stream() + .map(Node::getDependency) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + assertEquals(deps, deps2); + for (Dependency dep : deps2) { + dep.getVersion(); + } + } } diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.jar similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.jar diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1 similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1 rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1 diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1 similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1 rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1 diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1 similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1 rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1 diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1 similarity index 100% rename from maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1 rename to maven-core/src/test/resources/apiv4-repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1 diff --git a/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar new file mode 100644 index 0000000000..b376ffc16f Binary files /dev/null and b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar differ diff --git a/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar.sha1 new file mode 100644 index 0000000000..a0369caaef --- /dev/null +++ b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.jar.sha1 @@ -0,0 +1 @@ +cdd00374f1fee76b11e2a9d127405aa3f6be5b6a \ No newline at end of file diff --git a/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom new file mode 100644 index 0000000000..428715884b --- /dev/null +++ b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom @@ -0,0 +1,587 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.1</version> + + <name>JUnit</name> + <description>JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.</description> + <url>http://junit.org</url> + <inceptionYear>2002</inceptionYear> + <organization> + <name>JUnit</name> + <url>http://www.junit.org</url> + </organization> + <licenses> + <license> + <name>Eclipse Public License 1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + </license> + </licenses> + + <developers> + <developer> + <id>dsaff</id> + <name>David Saff</name> + <email>da...@saff.net</email> + </developer> + <developer> + <id>kcooney</id> + <name>Kevin Cooney</name> + <email>kcoo...@google.com</email> + </developer> + <developer> + <id>stefanbirkner</id> + <name>Stefan Birkner</name> + <email>m...@stefan-birkner.de</email> + </developer> + <developer> + <id>marcphilipp</id> + <name>Marc Philipp</name> + <email>m...@marcphilipp.de</email> + </developer> + </developers> + <contributors> + <contributor> + <name>JUnit contributors</name> + <organization>JUnit</organization> + <email>t...@junit.org</email> + <url>https://github.com/junit-team/junit4/graphs/contributors</url> + <roles> + <role>developers</role> + </roles> + </contributor> + </contributors> + + <prerequisites> + <maven>3.0.4</maven> + </prerequisites> + + <scm> + <connection>scm:git:git://github.com/junit-team/junit4.git</connection> + <developerConnection>scm:git:g...@github.com:junit-team/junit4.git</developerConnection> + <url>https://github.com/junit-team/junit4</url> + <tag>r4.13.1</tag> + </scm> + <issueManagement> + <system>github</system> + <url>https://github.com/junit-team/junit4/issues</url> + </issueManagement> + <ciManagement> + <system>travis</system> + <url>https://travis-ci.org/junit-team/junit4</url> + </ciManagement> + <distributionManagement> + <downloadUrl>https://github.com/junit-team/junit4/wiki/Download-and-Install</downloadUrl> + <snapshotRepository> + <id>junit-snapshot-repo</id> + <name>Nexus Snapshot Repository</name> + <url>https://oss.sonatype.org/content/repositories/snapshots/</url> + </snapshotRepository> + <repository> + <id>junit-releases-repo</id> + <name>Nexus Release Repository</name> + <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> + </repository> + <site> + <id>junit.github.io</id> + <url>gitsite:g...@github.com/junit-team/junit4.git</url> + </site> + </distributionManagement> + + <properties> + <jdkVersion>1.5</jdkVersion> + <surefireVersion>2.19.1</surefireVersion> + <hamcrestVersion>1.3</hamcrestVersion> + <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding> + <arguments /> + <gpg.keyname>67893CC4</gpg.keyname> + </properties> + + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + <version>${hamcrestVersion}</version> + </dependency> + + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + <version>${hamcrestVersion}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <resources> + <resource> + <directory>${project.basedir}/src/main/resources</directory> + </resource> + <resource> + <directory>${project.basedir}</directory> + <includes> + <include>LICENSE-junit.txt</include> + </includes> + </resource> + </resources> + <plugins> + <!-- + Both "org.apache" and "org.codehaus" are default providers of MOJO plugins + which are especially dedicated to Maven projects. + The MOJO stands for "Maven plain Old Java Object". + Each mojo is an executable goal in Maven, and a plugin is a distribution of + one or more related mojos. + For more information see http://maven.apache.org/plugin-developers/index.html + + The following plugins are ordered according the Maven build lifecycle. + http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html + --> + <plugin> + <!-- + Checks that the version of user's maven installation is 3.0.4, + the JDK is 1.5+, no non-standard repositories are specified in + the project, requires only release versions of dependencies of other artifacts. + --> + <artifactId>maven-enforcer-plugin</artifactId> + <version>1.4</version> + <executions> + <execution> + <id>enforce-versions</id> + <phase>initialize</phase> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <fail>true</fail> + <rules> + <requireMavenVersion> + <!-- Some plugin features require a recent Maven runtime to work properly --> + <message>Current version of Maven ${maven.version} required to build the project + should be ${project.prerequisites.maven}, or higher! + </message> + <version>[${project.prerequisites.maven},)</version> + </requireMavenVersion> + <requireJavaVersion> + <message>Current JDK version ${java.version} should be ${jdkVersion}, or higher! + </message> + <version>${jdkVersion}</version> + </requireJavaVersion> + <requireNoRepositories> + <message>Best Practice is to never define repositories in pom.xml (use a repository + manager instead). + </message> + </requireNoRepositories> + <requireReleaseDeps> + <message>No Snapshots Dependencies Allowed!</message> + </requireReleaseDeps> + </rules> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <!-- + Updates Version#id(). + --> + <groupId>com.google.code.maven-replacer-plugin</groupId> + <artifactId>replacer</artifactId> + <version>1.5.3</version> + <executions> + <execution> + <phase>process-sources</phase> + <goals> + <goal>replace</goal> + </goals> + </execution> + </executions> + <configuration> + <ignoreMissingFile>false</ignoreMissingFile> + <file>${project.build.sourceDirectory}/junit/runner/Version.java.template</file> + <outputFile>${project.build.sourceDirectory}/junit/runner/Version.java</outputFile> + <regex>false</regex> + <token>@version@</token> + <value>${project.version}</value> + </configuration> + </plugin> + <plugin><!-- Using jdk 1.5.0_22, package-info.java files are compiled correctly. --> + <!-- + java compiler plugin forked in extra process + --> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.3</version> + <configuration> + <encoding>${project.build.sourceEncoding}</encoding> + <source>${jdkVersion}</source> + <target>${jdkVersion}</target> + <testSource>${jdkVersion}</testSource> + <testTarget>${jdkVersion}</testTarget> + <compilerVersion>1.5</compilerVersion> + <showDeprecation>true</showDeprecation> + <showWarnings>true</showWarnings> + <debug>true</debug> + <fork>true</fork> + <compilerArgs> + <arg>-Xlint:unchecked</arg> + </compilerArgs> + <maxmem>128m</maxmem> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>animal-sniffer-maven-plugin</artifactId> + <version>1.14</version> + <executions> + <execution> + <id>signature-check</id> + <phase>test</phase> + <goals> + <goal>check</goal> + </goals> + <configuration> + <signature> + <groupId>org.codehaus.mojo.signature</groupId> + <artifactId>java15</artifactId> + <version>1.0</version> + </signature> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <!-- + A plugin which uses the JUnit framework in order to start + our junit suite "AllTests" after the sources are compiled. + --> + <artifactId>maven-surefire-plugin</artifactId> + <version>${surefireVersion}</version> + <configuration> + <test>org/junit/tests/AllTests.java</test> + <useSystemClassLoader>true</useSystemClassLoader> + <enableAssertions>false</enableAssertions> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefireVersion}</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <!-- + This plugin can package the main artifact's sources (src/main/java) + in to jar archive. See target/junit-*-sources.jar. + --> + <artifactId>maven-source-plugin</artifactId> + <version>2.4</version> + </plugin> + <plugin> + <!-- + This plugin can generate Javadoc by a forked + process and then package the Javadoc + in jar archive target/junit-*-javadoc.jar. + --> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.10.3</version> + <configuration> + <stylesheetfile>${basedir}/src/main/javadoc/stylesheet.css</stylesheetfile> + <show>protected</show> + <author>false</author> + <version>false</version> + <detectLinks>false</detectLinks> + <linksource>true</linksource> + <keywords>true</keywords> + <use>true</use> + <windowtitle>JUnit API</windowtitle> + <encoding>UTF-8</encoding> + <locale>en</locale> + <javadocVersion>${jdkVersion}</javadocVersion> + <javaApiLinks> + <property> + <name>api_${jdkVersion}</name> + <value>http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/</value> + </property> + </javaApiLinks> + <excludePackageNames>*.internal.*</excludePackageNames> + <verbose>true</verbose> + <minmemory>32m</minmemory> + <maxmemory>128m</maxmemory> + <failOnError>true</failOnError> + <includeDependencySources>true</includeDependencySources> + <dependencySourceIncludes> + <dependencySourceInclude>org.hamcrest:hamcrest-core:*</dependencySourceInclude> + </dependencySourceIncludes> + </configuration> + </plugin> + <plugin> + <artifactId>maven-release-plugin</artifactId> + <version>2.5.2</version> + <configuration> + <mavenExecutorId>forked-path</mavenExecutorId> + <useReleaseProfile>false</useReleaseProfile> + <arguments>-Pgenerate-docs,junit-release ${arguments}</arguments> + <tagNameFormat>r@{project.version}</tagNameFormat> + </configuration> + </plugin> + <plugin> + <artifactId>maven-site-plugin</artifactId> + <version>3.4</version> + <dependencies> + <dependency> + <groupId>com.github.stephenc.wagon</groupId> + <artifactId>wagon-gitsite</artifactId> + <version>0.4.1</version> + </dependency> + <dependency> + <groupId>org.apache.maven.doxia</groupId> + <artifactId>doxia-module-markdown</artifactId> + <version>1.5</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <version>2.6</version> + <configuration> + <archive> + <addMavenDescriptor>false</addMavenDescriptor> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + </manifest> + <manifestEntries> + <Automatic-Module-Name>junit</Automatic-Module-Name> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <artifactId>maven-clean-plugin</artifactId> + <version>2.6.1</version> + </plugin> + <plugin> + <artifactId>maven-deploy-plugin</artifactId> + <version>2.8.2</version> + </plugin> + <plugin> + <artifactId>maven-install-plugin</artifactId> + <version>2.5.2</version> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.7</version> + </plugin> + </plugins> + </build> + + <reporting> + <plugins> + <plugin> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>2.8</version> + <configuration> + <dependencyLocationsEnabled>false</dependencyLocationsEnabled> + <!-- waiting for MPIR-267 --> + </configuration> + <reportSets> + <reportSet> + <reports> + <report>index</report> + <report>dependency-info</report> + <report>modules</report> + <report>license</report> + <report>project-team</report> + <report>scm</report> + <report>issue-tracking</report> + <report>mailing-list</report> + <report>dependency-management</report> + <report>dependencies</report> + <report>dependency-convergence</report> + <report>cim</report> + <report>distribution-management</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.10.3</version> + <configuration> + <destDir>javadoc/latest</destDir> + <stylesheetfile>${basedir}/src/main/javadoc/stylesheet.css</stylesheetfile> + <show>protected</show> + <author>false</author> + <version>false</version> + <detectLinks>false</detectLinks> + <linksource>true</linksource> + <keywords>true</keywords> + <use>true</use> + <windowtitle>JUnit API</windowtitle> + <encoding>UTF-8</encoding> + <locale>en</locale> + <javadocVersion>${jdkVersion}</javadocVersion> + <javaApiLinks> + <property> + <name>api_${jdkVersion}</name> + <value>http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/</value> + </property> + </javaApiLinks> + <excludePackageNames>junit.*,*.internal.*</excludePackageNames> + <verbose>true</verbose> + <minmemory>32m</minmemory> + <maxmemory>128m</maxmemory> + <failOnError>true</failOnError> + <includeDependencySources>true</includeDependencySources> + <dependencySourceIncludes> + <dependencySourceInclude>org.hamcrest:hamcrest-core:*</dependencySourceInclude> + </dependencySourceIncludes> + </configuration> + <reportSets> + <reportSet> + <reports> + <report>javadoc</report> + </reports> + </reportSet> + </reportSets> + </plugin> + </plugins> + </reporting> + + <profiles> + <profile> + <id>junit-release</id> + <!-- + Signs all artifacts before deploying to Maven Central. + --> + <build> + <plugins> + <plugin> + <!-- + The goal is to sign all artifacts so that the user may verify them before downloading. + The automatic build system may reuire your key ID, and passphrase specified using system properties: + -Dgpg.passphrase="<passphrase>" -Dgpg.keyname="<your key ID>" + In order to create the key pair, use the command "gpg ––gen-key". + (–– stands for double dash) + --> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <executions> + <execution> + <id>gpg-sign</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>generate-docs</id> + <!-- + Generate the documentation artifacts. + Note: this profile is also required to be active for release + builds due to the packaging requirements of the Central repo + --> + <build> + <plugins> + <plugin> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-sources</id> + <phase>prepare-package</phase> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <executions> + <execution> + <id>attach-javadoc</id> + <phase>package</phase> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>restrict-doclint</id> + <!-- doclint is only supported by JDK 8 --> + <activation> + <jdk>[1.8,)</jdk> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <compilerArgs> + <arg>-Xlint:unchecked</arg> + <arg>-Xdoclint:accessibility,reference,syntax</arg> + </compilerArgs> + </configuration> + </plugin> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <additionalparam>-Xdoclint:accessibility -Xdoclint:reference</additionalparam> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <additionalparam>-Xdoclint:accessibility -Xdoclint:reference</additionalparam> + </configuration> + </plugin> + </plugins> + </reporting> + </profile> + <profile> + <id>java9</id> + <activation> + <jdk>[1.9,)</jdk> + </activation> + <properties> + <!-- JDK 9 minimal source and target versions are 1.6 --> + <jdkVersion>1.6</jdkVersion> + </properties> + <build> + <plugins> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <source>1.6</source> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <source>1.6</source> + </configuration> + </plugin> + </plugins> + </reporting> + </profile> + </profiles> +</project> diff --git a/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom.sha1 new file mode 100644 index 0000000000..d843b12bac --- /dev/null +++ b/maven-core/src/test/resources/apiv4-repo/junit/junit/4.13.1/junit-4.13.1.pom.sha1 @@ -0,0 +1 @@ +643e8b4c40dca9f0b0abd8125d378d9f47d7d69e \ No newline at end of file diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index b4c5153718..78c36e8d2d 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java @@ -76,7 +76,7 @@ import org.apache.maven.model.resolution.WorkspaceModelResolver; import org.apache.maven.model.superpom.SuperPomProvider; import org.apache.maven.model.validation.DefaultModelValidator; import org.apache.maven.model.validation.ModelValidator; -import org.apache.maven.model.version.VersionParser; +import org.apache.maven.model.version.ModelVersionParser; import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.MapBasedValueSource; import org.codehaus.plexus.interpolation.StringSearchInterpolator; @@ -110,7 +110,7 @@ public class DefaultModelBuilder implements ModelBuilder { private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; private final ModelVersionProcessor versionProcessor; private final ModelSourceTransformer transformer; - private final VersionParser versionParser; + private final ModelVersionParser versionParser; @SuppressWarnings("checkstyle:ParameterNumber") @Inject @@ -134,7 +134,7 @@ public class DefaultModelBuilder implements ModelBuilder { ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, ModelVersionProcessor versionProcessor, ModelSourceTransformer transformer, - VersionParser versionParser) { + ModelVersionParser versionParser) { this.modelProcessor = modelProcessor; this.modelValidator = modelValidator; this.modelNormalizer = modelNormalizer; diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java index de7b99eb6c..7fcdeb30a7 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java @@ -21,6 +21,7 @@ package org.apache.maven.model.building; import java.util.Arrays; import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; import org.apache.maven.api.spi.ModelParser; import org.apache.maven.model.Model; @@ -73,7 +74,7 @@ import org.apache.maven.model.superpom.DefaultSuperPomProvider; import org.apache.maven.model.superpom.SuperPomProvider; import org.apache.maven.model.validation.DefaultModelValidator; import org.apache.maven.model.validation.ModelValidator; -import org.apache.maven.model.version.VersionParser; +import org.apache.maven.model.version.ModelVersionParser; import static java.util.Objects.requireNonNull; @@ -106,7 +107,7 @@ public class DefaultModelBuilderFactory { private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; private ModelVersionProcessor versionProcessor; private ModelSourceTransformer transformer; - private VersionParser versionParser; + private ModelVersionParser versionParser; public DefaultModelBuilderFactory setModelProcessor(ModelProcessor modelProcessor) { this.modelProcessor = modelProcessor; @@ -214,7 +215,7 @@ public class DefaultModelBuilderFactory { return this; } - public DefaultModelBuilderFactory setModelVersionParser(VersionParser versionParser) { + public DefaultModelBuilderFactory setModelVersionParser(ModelVersionParser versionParser) { this.versionParser = versionParser; return this; } @@ -337,10 +338,10 @@ public class DefaultModelBuilderFactory { return new BuildModelSourceTransformer(); } - private VersionParser newModelVersionParser() { + private ModelVersionParser newModelVersionParser() { // This is a limited parser that does not support ranges and compares versions as strings // in real-life this parser should not be used, but replaced with a proper one - return new VersionParser() { + return new ModelVersionParser() { @Override public Version parseVersion(String version) { requireNonNull(version, "version"); @@ -361,6 +362,11 @@ public class DefaultModelBuilderFactory { public VersionRange parseVersionRange(String range) { throw new IllegalArgumentException("ranges not supported by this parser"); } + + @Override + public VersionConstraint parseVersionConstraint(String constraint) { + throw new IllegalArgumentException("constraint not supported by this parser"); + } }; } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/version/VersionParser.java b/maven-model-builder/src/main/java/org/apache/maven/model/version/ModelVersionParser.java similarity index 79% rename from maven-model-builder/src/main/java/org/apache/maven/model/version/VersionParser.java rename to maven-model-builder/src/main/java/org/apache/maven/model/version/ModelVersionParser.java index f6eaebefe8..134be60271 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/version/VersionParser.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/version/ModelVersionParser.java @@ -19,6 +19,7 @@ package org.apache.maven.model.version; import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.services.VersionParserException; @@ -30,7 +31,7 @@ import org.apache.maven.api.services.VersionParserException; * * @since 4.0.0 */ -public interface VersionParser { +public interface ModelVersionParser { /** * Parses the specified version string, for example "1.0". @@ -51,4 +52,14 @@ public interface VersionParser { */ @Nonnull VersionRange parseVersionRange(@Nonnull String range); + + /** + * Parses the specified version constraint specification, for example "1.0" or "[1.0,2.0)". + * + * @param constraint the range specification to parse, must not be {@code null} + * @return the parsed version constraint, never {@code null} + * @throws VersionParserException if the range specification violates the syntax rules of this scheme + */ + @Nonnull + VersionConstraint parseVersionConstraint(@Nonnull String constraint); } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelVersionParser.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelVersionParser.java index 02338cb728..c5e01b2472 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelVersionParser.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelVersionParser.java @@ -22,12 +22,11 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import java.util.Objects; - import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; import org.apache.maven.api.services.VersionParserException; -import org.apache.maven.model.version.VersionParser; +import org.apache.maven.model.version.ModelVersionParser; import org.eclipse.aether.version.InvalidVersionSpecificationException; import org.eclipse.aether.version.VersionScheme; @@ -35,7 +34,7 @@ import static java.util.Objects.requireNonNull; @Named @Singleton -public class DefaultModelVersionParser implements VersionParser { +public class DefaultModelVersionParser implements ModelVersionParser { private final VersionScheme versionScheme; @Inject @@ -55,10 +54,21 @@ public class DefaultModelVersionParser implements VersionParser { return new DefaultVersionRange(versionScheme, range); } + @Override + public VersionConstraint parseVersionConstraint(String constraint) { + requireNonNull(constraint, "constraint"); + return new DefaultVersionConstraint(versionScheme, constraint); + } + static class DefaultVersion implements Version { private final VersionScheme versionScheme; private final org.eclipse.aether.version.Version delegate; + DefaultVersion(VersionScheme versionScheme, org.eclipse.aether.version.Version delegate) { + this.versionScheme = versionScheme; + this.delegate = delegate; + } + DefaultVersion(VersionScheme versionScheme, String delegateValue) { this.versionScheme = versionScheme; try { @@ -91,7 +101,7 @@ public class DefaultModelVersionParser implements VersionParser { @Override public int hashCode() { - return Objects.hash(delegate); + return delegate.hashCode(); } @Override @@ -109,6 +119,11 @@ public class DefaultModelVersionParser implements VersionParser { private final VersionScheme versionScheme; private final org.eclipse.aether.version.VersionRange delegate; + DefaultVersionRange(VersionScheme versionScheme, org.eclipse.aether.version.VersionRange delegate) { + this.versionScheme = versionScheme; + this.delegate = delegate; + } + DefaultVersionRange(VersionScheme versionScheme, String delegateValue) { this.versionScheme = versionScheme; try { @@ -127,14 +142,135 @@ public class DefaultModelVersionParser implements VersionParser { } } + @Override + public Boundary getUpperBoundary() { + org.eclipse.aether.version.VersionRange.Bound bound = delegate.getUpperBound(); + if (bound == null) { + return null; + } + return new Boundary() { + @Override + public Version getVersion() { + return new DefaultVersion(versionScheme, bound.getVersion()); + } + + @Override + public boolean isInclusive() { + return bound.isInclusive(); + } + }; + } + + @Override + public Boundary getLowerBoundary() { + org.eclipse.aether.version.VersionRange.Bound bound = delegate.getLowerBound(); + if (bound == null) { + return null; + } + return new Boundary() { + @Override + public Version getVersion() { + return new DefaultVersion(versionScheme, bound.getVersion()); + } + + @Override + public boolean isInclusive() { + return bound.isInclusive(); + } + }; + } + + @Override + public String asString() { + return delegate.toString(); + } + + @Override + public String toString() { + return asString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultVersionRange that = (DefaultVersionRange) o; + return delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + } + + static class DefaultVersionConstraint implements VersionConstraint { + private final VersionScheme versionScheme; + private final org.eclipse.aether.version.VersionConstraint delegate; + + DefaultVersionConstraint(VersionScheme versionScheme, String delegateValue) { + this.versionScheme = versionScheme; + try { + this.delegate = versionScheme.parseVersionConstraint(delegateValue); + } catch (InvalidVersionSpecificationException e) { + throw new VersionParserException("Unable to parse version constraint: " + delegateValue, e); + } + } + + @Override + public boolean contains(Version version) { + if (version instanceof DefaultVersion) { + return delegate.containsVersion(((DefaultVersion) version).delegate); + } else { + return contains(new DefaultVersion(versionScheme, version.asString())); + } + } + @Override public String asString() { return delegate.toString(); } + @Override + public VersionRange getVersionRange() { + if (delegate.getRange() == null) { + return null; + } + return new DefaultVersionRange(versionScheme, delegate.getRange()); + } + + @Override + public Version getRecommendedVersion() { + if (delegate.getVersion() == null) { + return null; + } + return new DefaultVersion(versionScheme, delegate.getVersion()); + } + @Override public String toString() { return asString(); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultVersionConstraint that = (DefaultVersionConstraint) o; + return delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } } } diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractVersionTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractVersionTest.java new file mode 100644 index 0000000000..78b6b54bfe --- /dev/null +++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractVersionTest.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.repository.internal; + +import org.apache.maven.api.Version; + +import static org.junit.jupiter.api.Assertions.*; + +/** + */ +abstract class AbstractVersionTest { + + protected static final int X_LT_Y = -1; + + protected static final int X_EQ_Y = 0; + + protected static final int X_GT_Y = 1; + + protected abstract Version newVersion(String version); + + protected void assertOrder(int expected, String version1, String version2) { + Version v1 = newVersion(version1); + Version v2 = newVersion(version2); + + if (expected > 0) { + assertEquals(1, Integer.signum(v1.compareTo(v2)), "expected " + v1 + " > " + v2); + assertEquals(-1, Integer.signum(v2.compareTo(v1)), "expected " + v2 + " < " + v1); + assertNotEquals(v1, v2, "expected " + v1 + " != " + v2); + assertNotEquals(v2, v1, "expected " + v2 + " != " + v1); + } else if (expected < 0) { + assertEquals(-1, Integer.signum(v1.compareTo(v2)), "expected " + v1 + " < " + v2); + assertEquals(1, Integer.signum(v2.compareTo(v1)), "expected " + v2 + " > " + v1); + assertNotEquals(v1, v2, "expected " + v1 + " != " + v2); + assertNotEquals(v2, v1, "expected " + v2 + " != " + v1); + } else { + assertEquals(0, v1.compareTo(v2), "expected " + v1 + " == " + v2); + assertEquals(0, v2.compareTo(v1), "expected " + v2 + " == " + v1); + assertEquals(v1, v2, "expected " + v1 + " == " + v2); + assertEquals(v2, v1, "expected " + v2 + " == " + v1); + assertEquals(v1.hashCode(), v2.hashCode(), "expected #(" + v1 + ") == #(" + v1 + ")"); + } + } + + protected void assertSequence(String... versions) { + for (int i = 0; i < versions.length - 1; i++) { + for (int j = i + 1; j < versions.length; j++) { + assertOrder(X_LT_Y, versions[i], versions[j]); + } + } + } +} diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/ModelVersionParserTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/ModelVersionParserTest.java new file mode 100644 index 0000000000..90203267f6 --- /dev/null +++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/ModelVersionParserTest.java @@ -0,0 +1,101 @@ +/* + * 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.repository.internal; + +import org.apache.maven.api.VersionConstraint; +import org.apache.maven.api.services.VersionParserException; +import org.apache.maven.model.version.ModelVersionParser; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + */ +public class ModelVersionParserTest { + + private final ModelVersionParser versionParser = new DefaultModelVersionParser(new GenericVersionScheme()); + + private VersionParserException parseInvalid(String constraint) { + try { + versionParser.parseVersionConstraint(constraint); + fail("expected exception for constraint " + constraint); + return null; + } catch (VersionParserException e) { + return e; + } + } + + @Test + void testEnumeratedVersions() throws VersionParserException { + VersionConstraint c = versionParser.parseVersionConstraint("1.0"); + assertEquals("1.0", c.getRecommendedVersion().toString()); + assertTrue(c.contains(versionParser.parseVersion("1.0"))); + + c = versionParser.parseVersionConstraint("[1.0]"); + assertNull(c.getRecommendedVersion()); + assertTrue(c.contains(versionParser.parseVersion("1.0"))); + + c = versionParser.parseVersionConstraint("[1.0],[2.0]"); + assertTrue(c.contains(versionParser.parseVersion("1.0"))); + assertTrue(c.contains(versionParser.parseVersion("2.0"))); + + c = versionParser.parseVersionConstraint("[1.0],[2.0],[3.0]"); + assertContains(c, "1.0", "2.0", "3.0"); + assertNotContains(c, "1.5"); + + c = versionParser.parseVersionConstraint("[1,3),(3,5)"); + assertContains(c, "1", "2", "4"); + assertNotContains(c, "3", "5"); + + c = versionParser.parseVersionConstraint("[1,3),(3,)"); + assertContains(c, "1", "2", "4"); + assertNotContains(c, "3"); + } + + private void assertNotContains(VersionConstraint c, String... versions) { + assertContains(String.format("%s: %%s should not be contained\n", c.toString()), c, false, versions); + } + + private void assertContains(String msg, VersionConstraint c, boolean b, String... versions) { + for (String v : versions) { + assertEquals(b, c.contains(versionParser.parseVersion(v)), String.format(msg, v)); + } + } + + private void assertContains(VersionConstraint c, String... versions) { + assertContains(String.format("%s: %%s should be contained\n", c.toString()), c, true, versions); + } + + @Test + void testInvalid() { + parseInvalid("[1,"); + parseInvalid("[1,2],(3,"); + parseInvalid("[1,2],3"); + } + + @Test + void testSameUpperAndLowerBound() throws VersionParserException { + VersionConstraint c = versionParser.parseVersionConstraint("[1.0]"); + assertEquals("[1.0,1.0]", c.toString()); + VersionConstraint c2 = versionParser.parseVersionConstraint(c.toString()); + assertEquals(c, c2); + assertTrue(c.contains(versionParser.parseVersion("1.0"))); + } +} diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionRangeTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionRangeTest.java new file mode 100644 index 0000000000..23a982d903 --- /dev/null +++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionRangeTest.java @@ -0,0 +1,142 @@ +/* + * 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.repository.internal; + +import org.apache.maven.api.Version; +import org.apache.maven.api.VersionRange; +import org.apache.maven.api.services.VersionParserException; +import org.apache.maven.model.version.ModelVersionParser; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class VersionRangeTest { + + private ModelVersionParser versionParser = new DefaultModelVersionParser(new GenericVersionScheme()); + + private Version newVersion(String version) { + return versionParser.parseVersion(version); + } + + private VersionRange parseValid(String range) { + try { + return versionParser.parseVersionRange(range); + } catch (VersionParserException e) { + throw new AssertionError(range + " should be valid but failed to parse due to: " + e.getMessage(), e); + } + } + + private void parseInvalid(String range) { + try { + versionParser.parseVersionRange(range); + fail(range + " should be invalid"); + } catch (VersionParserException e) { + assertTrue(true); + } + } + + private void assertContains(VersionRange range, String version) { + assertTrue(range.contains(newVersion(version)), range + " should contain " + version); + } + + private void assertNotContains(VersionRange range, String version) { + assertFalse(range.contains(newVersion(version)), range + " should not contain " + version); + } + + @Test + void testLowerBoundInclusiveUpperBoundInclusive() { + VersionRange range = parseValid("[1,2]"); + assertContains(range, "1"); + assertContains(range, "1.1-SNAPSHOT"); + assertContains(range, "2"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testLowerBoundInclusiveUpperBoundExclusive() { + VersionRange range = parseValid("[1.2.3.4.5,1.2.3.4.6)"); + assertContains(range, "1.2.3.4.5"); + assertNotContains(range, "1.2.3.4.6"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testLowerBoundExclusiveUpperBoundInclusive() { + VersionRange range = parseValid("(1a,1b]"); + assertNotContains(range, "1a"); + assertContains(range, "1b"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testLowerBoundExclusiveUpperBoundExclusive() { + VersionRange range = parseValid("(1,3)"); + assertNotContains(range, "1"); + assertContains(range, "2-SNAPSHOT"); + assertNotContains(range, "3"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testSingleVersion() { + VersionRange range = parseValid("[1]"); + assertContains(range, "1"); + assertEquals(range, parseValid(range.toString())); + + range = parseValid("[1,1]"); + assertContains(range, "1"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testSingleWildcardVersion() { + VersionRange range = parseValid("[1.2.*]"); + assertContains(range, "1.2-alpha-1"); + assertContains(range, "1.2-SNAPSHOT"); + assertContains(range, "1.2"); + assertContains(range, "1.2.9999999"); + assertNotContains(range, "1.3-rc-1"); + assertEquals(range, parseValid(range.toString())); + } + + @Test + void testMissingOpenCloseDelimiter() { + parseInvalid("1.0"); + } + + @Test + void testMissingOpenDelimiter() { + parseInvalid("1.0]"); + parseInvalid("1.0)"); + } + + @Test + void testMissingCloseDelimiter() { + parseInvalid("[1.0"); + parseInvalid("(1.0"); + } + + @Test + void testTooManyVersions() { + parseInvalid("[1,2,3]"); + parseInvalid("(1,2,3)"); + parseInvalid("[1,2,3)"); + } +} diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionTest.java new file mode 100644 index 0000000000..d9302037c0 --- /dev/null +++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/VersionTest.java @@ -0,0 +1,453 @@ +/* + * 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.repository.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Locale; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.maven.api.Version; +import org.apache.maven.model.version.ModelVersionParser; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.junit.jupiter.api.Test; + +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.Assertions.*; + +/** + */ +public class VersionTest extends AbstractVersionTest { + private final ModelVersionParser modelVersionParser = new DefaultModelVersionParser(new GenericVersionScheme()); + + protected Version newVersion(String version) { + return modelVersionParser.parseVersion(version); + } + + @Test + void testEmptyVersion() { + assertOrder(X_EQ_Y, "0", ""); + } + + @Test + void testNumericOrdering() { + assertOrder(X_LT_Y, "2", "10"); + assertOrder(X_LT_Y, "1.2", "1.10"); + assertOrder(X_LT_Y, "1.0.2", "1.0.10"); + assertOrder(X_LT_Y, "1.0.0.2", "1.0.0.10"); + assertOrder(X_LT_Y, "1.0.20101206.111434.1", "1.0.20101206.111435.1"); + assertOrder(X_LT_Y, "1.0.20101206.111434.2", "1.0.20101206.111434.10"); + } + + @Test + void testDelimiters() { + assertOrder(X_EQ_Y, "1.0", "1-0"); + assertOrder(X_EQ_Y, "1.0", "1_0"); + assertOrder(X_EQ_Y, "1.a", "1a"); + } + + @Test + void testLeadingZerosAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "01"); + assertOrder(X_EQ_Y, "1.2", "1.002"); + assertOrder(X_EQ_Y, "1.2.3", "1.2.0003"); + assertOrder(X_EQ_Y, "1.2.3.4", "1.2.3.00004"); + } + + @Test + void testTrailingZerosAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0"); + assertOrder(X_EQ_Y, "1", "1-0-0-0-0-0-0-0-0-0-0-0-0-0"); + assertOrder(X_EQ_Y, "1", "1.0-0.0-0.0-0.0-0.0-0.0-0.0"); + assertOrder(X_EQ_Y, "1", "1.0000000000000"); + assertOrder(X_EQ_Y, "1.0", "1.0.0"); + } + + @Test + void testTrailingZerosBeforeQualifierAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1.0-ga", "1.0.0-ga"); + assertOrder(X_EQ_Y, "1.0.ga", "1.0.0.ga"); + assertOrder(X_EQ_Y, "1.0ga", "1.0.0ga"); + + assertOrder(X_EQ_Y, "1.0-alpha", "1.0.0-alpha"); + assertOrder(X_EQ_Y, "1.0.alpha", "1.0.0.alpha"); + assertOrder(X_EQ_Y, "1.0alpha", "1.0.0alpha"); + assertOrder(X_EQ_Y, "1.0-alpha-snapshot", "1.0.0-alpha-snapshot"); + assertOrder(X_EQ_Y, "1.0.alpha.snapshot", "1.0.0.alpha.snapshot"); + + assertOrder(X_EQ_Y, "1.x.0-alpha", "1.x.0.0-alpha"); + assertOrder(X_EQ_Y, "1.x.0.alpha", "1.x.0.0.alpha"); + assertOrder(X_EQ_Y, "1.x.0-alpha-snapshot", "1.x.0.0-alpha-snapshot"); + assertOrder(X_EQ_Y, "1.x.0.alpha.snapshot", "1.x.0.0.alpha.snapshot"); + } + + @Test + void testTrailingDelimitersAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "1............."); + assertOrder(X_EQ_Y, "1", "1-------------"); + assertOrder(X_EQ_Y, "1.0", "1............."); + assertOrder(X_EQ_Y, "1.0", "1-------------"); + } + + @Test + void testInitialDelimiters() { + assertOrder(X_EQ_Y, "0.1", ".1"); + assertOrder(X_EQ_Y, "0.0.1", "..1"); + assertOrder(X_EQ_Y, "0.1", "-1"); + assertOrder(X_EQ_Y, "0.0.1", "--1"); + } + + @Test + void testConsecutiveDelimiters() { + assertOrder(X_EQ_Y, "1.0.1", "1..1"); + assertOrder(X_EQ_Y, "1.0.0.1", "1...1"); + assertOrder(X_EQ_Y, "1.0.1", "1--1"); + assertOrder(X_EQ_Y, "1.0.0.1", "1---1"); + } + + @Test + void testUnlimitedNumberOfVersionComponents() { + assertOrder(X_GT_Y, "1.0.1.2.3.4.5.6.7.8.9.0.1.2.10", "1.0.1.2.3.4.5.6.7.8.9.0.1.2.3"); + } + + @Test + void testUnlimitedNumberOfDigitsInNumericComponent() { + assertOrder(X_GT_Y, "1.1234567890123456789012345678901", "1.123456789012345678901234567891"); + } + + @Test + void testTransitionFromDigitToLetterAndViceVersaIsEqualivantToDelimiter() { + assertOrder(X_EQ_Y, "1alpha10", "1.alpha.10"); + assertOrder(X_EQ_Y, "1alpha10", "1-alpha-10"); + + assertOrder(X_GT_Y, "1.alpha10", "1.alpha2"); + assertOrder(X_GT_Y, "10alpha", "1alpha"); + } + + @Test + void testWellKnownQualifierOrdering() { + assertOrder(X_EQ_Y, "1-alpha1", "1-a1"); + assertOrder(X_LT_Y, "1-alpha", "1-beta"); + assertOrder(X_EQ_Y, "1-beta1", "1-b1"); + assertOrder(X_LT_Y, "1-beta", "1-milestone"); + assertOrder(X_EQ_Y, "1-milestone1", "1-m1"); + assertOrder(X_LT_Y, "1-milestone", "1-rc"); + assertOrder(X_EQ_Y, "1-rc", "1-cr"); + assertOrder(X_LT_Y, "1-rc", "1-snapshot"); + assertOrder(X_LT_Y, "1-snapshot", "1"); + assertOrder(X_EQ_Y, "1", "1-ga"); + assertOrder(X_EQ_Y, "1", "1.ga.0.ga"); + assertOrder(X_EQ_Y, "1.0", "1-ga"); + assertOrder(X_EQ_Y, "1", "1-ga.ga"); + assertOrder(X_EQ_Y, "1", "1-ga-ga"); + assertOrder(X_EQ_Y, "A", "A.ga.ga"); + assertOrder(X_EQ_Y, "A", "A-ga-ga"); + assertOrder(X_EQ_Y, "1", "1-final"); + assertOrder(X_EQ_Y, "1", "1-release"); + assertOrder(X_LT_Y, "1", "1-sp"); + + assertOrder(X_LT_Y, "A.rc.1", "A.ga.1"); + assertOrder(X_GT_Y, "A.sp.1", "A.ga.1"); + assertOrder(X_LT_Y, "A.rc.x", "A.ga.x"); + assertOrder(X_GT_Y, "A.sp.x", "A.ga.x"); + } + + @Test + void testWellKnownQualifierVersusUnknownQualifierOrdering() { + assertOrder(X_GT_Y, "1-abc", "1-alpha"); + assertOrder(X_GT_Y, "1-abc", "1-beta"); + assertOrder(X_GT_Y, "1-abc", "1-milestone"); + assertOrder(X_GT_Y, "1-abc", "1-rc"); + assertOrder(X_GT_Y, "1-abc", "1-snapshot"); + assertOrder(X_GT_Y, "1-abc", "1"); + assertOrder(X_GT_Y, "1-abc", "1-sp"); + } + + @Test + void testWellKnownSingleCharQualifiersOnlyRecognizedIfImmediatelyFollowedByNumber() { + assertOrder(X_GT_Y, "1.0a", "1.0"); + assertOrder(X_GT_Y, "1.0-a", "1.0"); + assertOrder(X_GT_Y, "1.0.a", "1.0"); + assertOrder(X_GT_Y, "1.0b", "1.0"); + assertOrder(X_GT_Y, "1.0-b", "1.0"); + assertOrder(X_GT_Y, "1.0.b", "1.0"); + assertOrder(X_GT_Y, "1.0m", "1.0"); + assertOrder(X_GT_Y, "1.0-m", "1.0"); + assertOrder(X_GT_Y, "1.0.m", "1.0"); + + assertOrder(X_LT_Y, "1.0a1", "1.0"); + assertOrder(X_LT_Y, "1.0-a1", "1.0"); + assertOrder(X_LT_Y, "1.0.a1", "1.0"); + assertOrder(X_LT_Y, "1.0b1", "1.0"); + assertOrder(X_LT_Y, "1.0-b1", "1.0"); + assertOrder(X_LT_Y, "1.0.b1", "1.0"); + assertOrder(X_LT_Y, "1.0m1", "1.0"); + assertOrder(X_LT_Y, "1.0-m1", "1.0"); + assertOrder(X_LT_Y, "1.0.m1", "1.0"); + + assertOrder(X_GT_Y, "1.0a.1", "1.0"); + assertOrder(X_GT_Y, "1.0a-1", "1.0"); + assertOrder(X_GT_Y, "1.0b.1", "1.0"); + assertOrder(X_GT_Y, "1.0b-1", "1.0"); + assertOrder(X_GT_Y, "1.0m.1", "1.0"); + assertOrder(X_GT_Y, "1.0m-1", "1.0"); + } + + @Test + void testUnknownQualifierOrdering() { + assertOrder(X_LT_Y, "1-abc", "1-abcd"); + assertOrder(X_LT_Y, "1-abc", "1-bcd"); + assertOrder(X_GT_Y, "1-abc", "1-aac"); + } + + @Test + void testCaseInsensitiveOrderingOfQualifiers() { + assertOrder(X_EQ_Y, "1.alpha", "1.ALPHA"); + assertOrder(X_EQ_Y, "1.alpha", "1.Alpha"); + + assertOrder(X_EQ_Y, "1.beta", "1.BETA"); + assertOrder(X_EQ_Y, "1.beta", "1.Beta"); + + assertOrder(X_EQ_Y, "1.milestone", "1.MILESTONE"); + assertOrder(X_EQ_Y, "1.milestone", "1.Milestone"); + + assertOrder(X_EQ_Y, "1.rc", "1.RC"); + assertOrder(X_EQ_Y, "1.rc", "1.Rc"); + assertOrder(X_EQ_Y, "1.cr", "1.CR"); + assertOrder(X_EQ_Y, "1.cr", "1.Cr"); + + assertOrder(X_EQ_Y, "1.snapshot", "1.SNAPSHOT"); + assertOrder(X_EQ_Y, "1.snapshot", "1.Snapshot"); + + assertOrder(X_EQ_Y, "1.ga", "1.GA"); + assertOrder(X_EQ_Y, "1.ga", "1.Ga"); + assertOrder(X_EQ_Y, "1.final", "1.FINAL"); + assertOrder(X_EQ_Y, "1.final", "1.Final"); + assertOrder(X_EQ_Y, "1.release", "1.RELEASE"); + assertOrder(X_EQ_Y, "1.release", "1.Release"); + + assertOrder(X_EQ_Y, "1.sp", "1.SP"); + assertOrder(X_EQ_Y, "1.sp", "1.Sp"); + + assertOrder(X_EQ_Y, "1.unknown", "1.UNKNOWN"); + assertOrder(X_EQ_Y, "1.unknown", "1.Unknown"); + } + + @Test + void testCaseInsensitiveOrderingOfQualifiersIsLocaleIndependent() { + Locale orig = Locale.getDefault(); + try { + Locale[] locales = {Locale.ENGLISH, new Locale("tr")}; + for (Locale locale : locales) { + Locale.setDefault(locale); + assertOrder(X_EQ_Y, "1-abcdefghijklmnopqrstuvwxyz", "1-ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + } finally { + Locale.setDefault(orig); + } + } + + @Test + void testQualifierVersusNumberOrdering() { + assertOrder(X_LT_Y, "1-ga", "1-1"); + assertOrder(X_LT_Y, "1.ga", "1.1"); + assertOrder(X_EQ_Y, "1-ga", "1.0"); + assertOrder(X_EQ_Y, "1.ga", "1.0"); + + assertOrder(X_LT_Y, "1-ga-1", "1-0-1"); + assertOrder(X_LT_Y, "1.ga.1", "1.0.1"); + + assertOrder(X_GT_Y, "1.sp", "1.0"); + assertOrder(X_LT_Y, "1.sp", "1.1"); + + assertOrder(X_LT_Y, "1-abc", "1-1"); + assertOrder(X_LT_Y, "1.abc", "1.1"); + + assertOrder(X_LT_Y, "1-xyz", "1-1"); + assertOrder(X_LT_Y, "1.xyz", "1.1"); + } + + @Test + void testVersionEvolution() { + assertSequence( + "0.9.9-SNAPSHOT", + "0.9.9", + "0.9.10-SNAPSHOT", + "0.9.10", + "1.0-alpha-2-SNAPSHOT", + "1.0-alpha-2", + "1.0-alpha-10-SNAPSHOT", + "1.0-alpha-10", + "1.0-beta-1-SNAPSHOT", + "1.0-beta-1", + "1.0-rc-1-SNAPSHOT", + "1.0-rc-1", + "1.0-SNAPSHOT", + "1.0", + "1.0-sp-1-SNAPSHOT", + "1.0-sp-1", + "1.0.1-alpha-1-SNAPSHOT", + "1.0.1-alpha-1", + "1.0.1-beta-1-SNAPSHOT", + "1.0.1-beta-1", + "1.0.1-rc-1-SNAPSHOT", + "1.0.1-rc-1", + "1.0.1-SNAPSHOT", + "1.0.1", + "1.1-SNAPSHOT", + "1.1"); + + assertSequence("1.0-alpha", "1.0", "1.0-1"); + assertSequence("1.0.alpha", "1.0", "1.0-1"); + assertSequence("1.0-alpha", "1.0", "1.0.1"); + assertSequence("1.0.alpha", "1.0", "1.0.1"); + } + + @Test + void testMinimumSegment() { + assertOrder(X_LT_Y, "1.min", "1.0-alpha-1"); + assertOrder(X_LT_Y, "1.min", "1.0-SNAPSHOT"); + assertOrder(X_LT_Y, "1.min", "1.0"); + assertOrder(X_LT_Y, "1.min", "1.9999999999"); + + assertOrder(X_EQ_Y, "1.min", "1.MIN"); + + assertOrder(X_GT_Y, "1.min", "0.99999"); + assertOrder(X_GT_Y, "1.min", "0.max"); + } + + @Test + void testMaximumSegment() { + assertOrder(X_GT_Y, "1.max", "1.0-alpha-1"); + assertOrder(X_GT_Y, "1.max", "1.0-SNAPSHOT"); + assertOrder(X_GT_Y, "1.max", "1.0"); + assertOrder(X_GT_Y, "1.max", "1.9999999999"); + + assertOrder(X_EQ_Y, "1.max", "1.MAX"); + + assertOrder(X_LT_Y, "1.max", "2.0-alpha-1"); + assertOrder(X_LT_Y, "1.max", "2.min"); + } + + /** + * UT for <a href="https://issues.apache.org/jira/browse/MRESOLVER-314">MRESOLVER-314</a>. + * + * Generates random UUID string based versions and tries to sort them. While this test is not as reliable + * as {@link #testCompareUuidVersionStringStream()}, it covers broader range and in case it fails it records + * the failed array, so we can investigate more. + */ + @Test + void testCompareUuidRandom() { + for (int j = 0; j < 32; j++) { + ArrayList<Version> versions = new ArrayList<>(); + for (int i = 0; i < 64; i++) { + versions.add(newVersion(UUID.randomUUID().toString())); + } + try { + Collections.sort(versions); + } catch (Exception e) { + e.printStackTrace(System.err); + System.err.println("The UUIDs used"); + System.err.println(versions.stream().map(Version::toString).collect(Collectors.joining("\n"))); + fail("unexpected exception"); + } + } + } + + /** + * UT for <a href="https://issues.apache.org/jira/browse/MRESOLVER-314">MRESOLVER-314</a>. + * + * Works on known set that failed before fix, provided by {@link #uuidVersionStringStream()}. + */ + @Test + void testCompareUuidVersionStringStream() { + // this operation below fails with IAEx if comparison is unstable + uuidVersionStringStream().map(this::newVersion).sorted().collect(toList()); + } + + private Stream<String> uuidVersionStringStream() { + return Stream.of( + "e3f6b227-e09d-4461-a030-b8c1755834f7", + "dfdf5e15-b047-4fee-94e5-3ddf6fe90a0c", + "bcc15412-6817-4b64-acef-169d048626f6", + "76093f07-ab1c-4cdd-ae92-9bb500ceed84", + "7ca8dc9f-4e73-459b-8f30-06aa7972f486", + "93fee46b-2715-4abd-877a-4197eb8601aa", + "0379da36-84ee-4d06-9388-83d3aa6536b5", + "4bb2c7a8-cf68-4ca5-8024-72dc93506da9", + "9dcc4cd1-34d2-4499-8dab-3ef8bca9680d", + "ea53d552-83ab-4f7d-852d-98951201083d", + "0bc420d2-4089-468b-bc54-0a4e2835feed", + "318d2433-fe40-4f28-9f3a-4e3d66d9b5fb", + "447b456c-81a4-4f24-9d2e-e5091c39cd19", + "85741f6e-26fe-40d0-a73a-283315409ab2", + "3165b9b2-9f8e-4117-ac70-87056eb45745", + "9d534bf3-a3b0-4a19-9809-670934c10752", + "86d78bba-d84e-4349-aea6-850721e78188", + "06392b8c-e26c-4a83-8ec2-085415bc513d", + "1fb13754-90be-42cb-bc7f-9b9211494e92", + "3018965c-3330-402a-8075-caa7613ec4fa", + "7ecc912b-4938-4411-895e-8ca7cf22ce02", + "6580ada2-4764-45a2-9789-98217d7cf5b6", + "be9d0de4-4ba7-4fdd-8f76-cb579168c549", + "7a8236d6-6bec-4176-b6a1-f869c02183c3", + "089f4195-881c-4f9e-8bc1-124531dee977", + "46ffda62-768a-4864-9581-cc75eafe1a67", + "1d6226f6-dacc-42a9-bd88-7aab1f59df74", + "0948ed55-c25e-4319-9801-5f817bac09b5", + "2fd52f5e-b856-47ad-9e58-45c1d0ba437b", + "6c325bd0-ac6b-4391-a5c5-caa160972fa2", + "d213f6be-f56b-42d2-abda-4300742e0add", + "efaae115-cc21-4b2e-a150-fb4e0d807736", + "30f872e8-9cb5-4b22-b65c-6819ca7a14ba", + "d8e5fb54-6e90-4f74-adb3-451abfbe76a8", + "b47d62b8-9256-47a1-8e21-21ba9639c212", + "b25da555-e1f7-4bc5-92fe-4c895d9c70d8", + "088f0de7-5973-4c10-a7ff-9f3cd7718572", + "b161de76-e5d5-4224-883b-a749b147d63d", + "19b7de96-09fa-4276-843d-c0fbdaf07767", + "e0503f73-33fd-4f9c-812f-8cae3a128c28", + "b8c57488-a42c-43ed-bfb9-acd112d6b68f", + "25997299-0825-4c9b-b0ed-75f935c63fd7", + "2b2e2fcd-3988-45af-855b-7646c0cdbfb5", + "4e6e16b9-2ae4-4593-b907-1febaf3988dc", + "ac8bd519-7fd4-4b85-8154-9dbb87f6cd4f", + "61473b39-b620-468b-abcf-16fe6adfd5cb", + "18e7a548-3f0b-492b-bc19-dce3eec736fa", + "c4d82839-3c46-4eff-b10c-ec0b5bcc600b", + "48f6e90f-924b-4859-9763-3ffe661f5af6", + "48852d79-ba23-475e-b675-a413b989a2a7", + "f7ee0915-ff00-4404-9e9a-6e753d5ff767", + "d6462359-a4e2-45ab-aedc-3b1849b0e6ca", + "e66228de-d1ed-4973-a108-c181d5059fdb", + "d49672a7-177d-475d-aad0-aab0ff4a11b7", + "bfa9337a-0489-4cba-b2db-e0d9d2424e4f", + "dc9bbe34-3c54-4c0f-a3cd-00e96604ae23", + "a8119cf1-9694-4b24-923a-3fc729b5f809", + "5d29cf45-3b9c-4697-85b8-86c81c6ec0c9", + "e3dcb4c2-a867-40f7-a3b1-fb1058a041e5", + "ae240754-2ea2-409a-a92c-648fc7a7b70b", + "8c187383-d59b-4e49-8dfd-98aa5f01925a", + "9b100ee6-71ed-4746-92c2-b5fb02af7ebd", + "f95e94f7-2443-4b2f-a10d-059d8d224dd9", + "b558af80-78bc-43c7-b916-d635a23cc4b5"); + } +}