This is an automated email from the ASF dual-hosted git repository.
sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-release.git
The following commit(s) were added to refs/heads/master by this push:
new 88630f90 Fixed #1426 : Replace archived `org.semver:api` with custom
`SemVer` implementation (#1430)
88630f90 is described below
commit 88630f903c60b170f3cd04325a4842182ce7d30a
Author: Harsh Mehta <[email protected]>
AuthorDate: Sun Nov 30 16:46:33 2025 +0530
Fixed #1426 : Replace archived `org.semver:api` with custom `SemVer`
implementation (#1430)
Signed-off-by: Harsh Mehta <[email protected]>
Co-authored-by: harsh-mehta-sb <[email protected]>
---
.../maven-release-semver-policy/pom.xml | 24 --
.../policy/semver/AbstractSemVerVersionPolicy.java | 11 +-
.../maven/shared/release/policy/semver/SemVer.java | 252 +++++++++++++++++++++
.../SemVerMajorDevelopmentVersionPolicy.java | 5 +-
.../semver/SemVerMajorReleaseVersionPolicy.java | 5 +-
.../SemVerMinorDevelopmentVersionPolicy.java | 5 +-
.../semver/SemVerMinorReleaseVersionPolicy.java | 5 +-
.../SemVerPatchDevelopmentVersionPolicy.java | 5 +-
.../shared/release/policy/semver/SemVerTest.java | 147 ++++++++++++
9 files changed, 414 insertions(+), 45 deletions(-)
diff --git a/maven-release-policies/maven-release-semver-policy/pom.xml
b/maven-release-policies/maven-release-semver-policy/pom.xml
index 64b29079..19ff5742 100644
--- a/maven-release-policies/maven-release-semver-policy/pom.xml
+++ b/maven-release-policies/maven-release-semver-policy/pom.xml
@@ -39,30 +39,6 @@ under the License.
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>org.semver</groupId>
- <artifactId>api</artifactId>
- <version>0.9.33</version>
- <exclusions>
- <!-- only one class Version from semver api is used, avoid bringing in
unnecessary dependencies -->
- <exclusion>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </exclusion>
- <exclusion>
- <groupId>org.ow2.asm</groupId>
- <artifactId>*</artifactId>
- </exclusion>
- <exclusion>
- <groupId>de.tototec</groupId>
- <artifactId>de.tototec.cmdoption</artifactId>
- </exclusion>
- <exclusion>
- <groupId>com.google.code.findbugs</groupId>
- <artifactId>jsr305</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
<dependency>
<groupId>javax.inject</groupId>
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/AbstractSemVerVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/AbstractSemVerVersionPolicy.java
index 7b6b8037..ce30c2ee 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/AbstractSemVerVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/AbstractSemVerVersionPolicy.java
@@ -22,7 +22,6 @@ import
org.apache.maven.shared.release.policy.version.VersionPolicy;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Abstract base class for SemVer-based VersionPolicy implementations.
@@ -31,19 +30,19 @@ import org.semver.Version;
*/
abstract class AbstractSemVerVersionPolicy implements VersionPolicy {
- protected Version createVersionFromRequest(VersionPolicyRequest request)
throws VersionParseException {
+ protected SemVer createVersionFromRequest(VersionPolicyRequest request)
throws VersionParseException {
try {
- return Version.parse(request.getVersion());
+ return SemVer.parse(request.getVersion());
} catch (IllegalArgumentException e) {
throw new VersionParseException(e.getMessage());
}
}
- protected VersionPolicyResult createResult(Version version) {
+ protected VersionPolicyResult createResult(SemVer version) {
return new VersionPolicyResult().setVersion(version.toString());
}
- protected VersionPolicyResult createSnapshotResult(Version version) {
- return new VersionPolicyResult().setVersion(version.toString() +
"-SNAPSHOT");
+ protected VersionPolicyResult createSnapshotResult(SemVer version) {
+ return new
VersionPolicyResult().setVersion(version.toSnapshotVersion().toString());
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVer.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVer.java
new file mode 100644
index 00000000..ff88098b
--- /dev/null
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVer.java
@@ -0,0 +1,252 @@
+/*
+ * 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.shared.release.policy.semver;
+
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A simple Semantic Versioning 2.0.0 implementation.
+ * <p>
+ * This class provides basic parsing and manipulation of semantic version
strings
+ * following the format: MAJOR.MINOR.PATCH[-PRERELEASE][+METADATA]
+ * </p>
+ *
+ * @see <a href="https://semver.org/">Semantic Versioning 2.0.0</a>
+ */
+class SemVer {
+
+ /**
+ * Regex pattern for parsing semantic versions from semver.org.
+ * Groups: 1=major, 2=minor, 3=patch, 4=prerelease, 5=metadata
+ *
+ * @see <a
href="https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string">SemVer
Regex</a>
+ */
+ private static final Pattern SEMVER_PATTERN =
Pattern.compile("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"
+ + "(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)"
+ +
"(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
+
+ private final int major;
+ private final int minor;
+ private final int patch;
+ private final String preRelease;
+ private final String metadata;
+
+ /**
+ * Version element types that can be incremented.
+ */
+ public enum Element {
+ MAJOR,
+ MINOR,
+ PATCH
+ }
+
+ /**
+ * Constructs a new SemVer instance.
+ *
+ * @param major the major version number
+ * @param minor the minor version number
+ * @param patch the patch version number
+ * @param preRelease the pre-release identifier (can be null)
+ * @param metadata the build metadata (can be null)
+ */
+ protected SemVer(int major, int minor, int patch, String preRelease,
String metadata) {
+ if (major < 0 || minor < 0 || patch < 0) {
+ throw new IllegalArgumentException("Version numbers must be
non-negative");
+ }
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ this.preRelease = preRelease;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Parses a version string into a SemVer object.
+ *
+ * @param version the version string to parse
+ * @return the parsed SemVer object
+ * @throws IllegalArgumentException if the version string is invalid
+ */
+ static SemVer parse(String version) {
+ if (version == null || version.trim().isEmpty()) {
+ throw new IllegalArgumentException("Version string cannot be null
or empty");
+ }
+
+ Matcher matcher = SEMVER_PATTERN.matcher(version.trim());
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid semantic version
format: " + version);
+ }
+
+ int major = Integer.parseInt(matcher.group(1));
+ int minor = Integer.parseInt(matcher.group(2));
+ int patch = Integer.parseInt(matcher.group(3));
+ String preRelease = matcher.group(4);
+ String metadata = matcher.group(5);
+
+ return new SemVer(major, minor, patch, preRelease, metadata);
+ }
+
+ /**
+ * Returns a new SemVer with the release version (removes -SNAPSHOT and
any pre-release/metadata).
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>1.2.3-SNAPSHOT → 1.2.3</li>
+ * <li>1.2.3-beta+build → 1.2.3</li>
+ * <li>1.2.3 → 1.2.3</li>
+ * </ul>
+ *
+ * @return a new SemVer representing the release version
+ */
+ SemVer toReleaseVersion() {
+ return new SemVer(major, minor, patch, null, null);
+ }
+
+ /**
+ * Returns a new SemVer with -SNAPSHOT appended as pre-release identifier.
+ * If the version already has a pre-release identifier, it will be
replaced with SNAPSHOT.
+ * Metadata is removed.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>1.2.3 → 1.2.3-SNAPSHOT</li>
+ * <li>1.2.3-beta → 1.2.3-SNAPSHOT</li>
+ * <li>1.2.3+build → 1.2.3-SNAPSHOT</li>
+ * <li>1.2.3-SNAPSHOT → 1.2.3-SNAPSHOT (no change)</li>
+ * </ul>
+ *
+ * @return a new SemVer with SNAPSHOT pre-release identifier, or this
instance if already a SNAPSHOT version
+ */
+ SemVer toSnapshotVersion() {
+ if ("SNAPSHOT".equals(preRelease) && metadata == null) {
+ return this;
+ }
+ return new SemVer(major, minor, patch, "SNAPSHOT", null);
+ }
+
+ /**
+ * Returns a new SemVer with the specified element incremented.
+ * If the version has pre-release or metadata, returns the release version
without incrementing.
+ * Otherwise, increments the specified element and all lower elements are
reset to 0.
+ * Pre-release and metadata are always cleared in the result.
+ *
+ * @param element the element to increment (MAJOR, MINOR, or PATCH)
+ * @return a new SemVer with the specified element incremented (or release
version if pre-release/metadata present)
+ */
+ SemVer next(Element element) {
+ Objects.requireNonNull(element, "Element cannot be null");
+
+ // If version has pre-release or metadata, just return release version
without incrementing
+ if (hasPreRelease() || hasMetadata()) {
+ return toReleaseVersion();
+ }
+
+ switch (element) {
+ case MAJOR:
+ return new SemVer(major + 1, 0, 0, null, null);
+ case MINOR:
+ return new SemVer(major, minor + 1, 0, null, null);
+ case PATCH:
+ return new SemVer(major, minor, patch + 1, null, null);
+ default:
+ throw new IllegalArgumentException("Unknown element: " +
element);
+ }
+ }
+
+ /**
+ * Checks if this version has a pre-release identifier.
+ *
+ * @return true if pre-release identifier is present, false otherwise
+ */
+ private boolean hasPreRelease() {
+ return preRelease != null && !preRelease.isEmpty();
+ }
+
+ /**
+ * Checks if this version has build metadata.
+ *
+ * @return true if build metadata is present, false otherwise
+ */
+ private boolean hasMetadata() {
+ return metadata != null && !metadata.isEmpty();
+ }
+
+ /**
+ * Returns the major version number.
+ *
+ * @return the major version
+ */
+ int getMajor() {
+ return major;
+ }
+
+ /**
+ * Returns the minor version number.
+ *
+ * @return the minor version
+ */
+ int getMinor() {
+ return minor;
+ }
+
+ /**
+ * Returns the patch version number.
+ *
+ * @return the patch version
+ */
+ int getPatch() {
+ return patch;
+ }
+
+ /**
+ * Returns the pre-release identifier.
+ *
+ * @return the pre-release identifier, or null if not present
+ */
+ String getPreRelease() {
+ return preRelease;
+ }
+
+ /**
+ * Returns the build metadata.
+ *
+ * @return the build metadata, or null if not present
+ */
+ String getMetadata() {
+ return metadata;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(major).append('.').append(minor).append('.').append(patch);
+
+ if (preRelease != null && !preRelease.isEmpty()) {
+ sb.append('-').append(preRelease);
+ }
+
+ if (metadata != null && !metadata.isEmpty()) {
+ sb.append('+').append(metadata);
+ }
+
+ return sb.toString();
+ }
+}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorDevelopmentVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorDevelopmentVersionPolicy.java
index 567947a6..2bdb8012 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorDevelopmentVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorDevelopmentVersionPolicy.java
@@ -24,7 +24,6 @@ import javax.inject.Singleton;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Uses SemVer implementation to increase major element when resolving the
development version.
@@ -37,13 +36,13 @@ class SemVerMajorDevelopmentVersionPolicy extends
AbstractSemVerVersionPolicy {
@Override
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request)
throws VersionParseException {
- Version version = createVersionFromRequest(request).toReleaseVersion();
+ SemVer version = createVersionFromRequest(request).toReleaseVersion();
return createResult(version);
}
@Override
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest
request) throws VersionParseException {
- Version version =
createVersionFromRequest(request).next(Version.Element.MAJOR);
+ SemVer version =
createVersionFromRequest(request).next(SemVer.Element.MAJOR);
return createSnapshotResult(version);
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorReleaseVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorReleaseVersionPolicy.java
index b2c97960..09ecc784 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorReleaseVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorReleaseVersionPolicy.java
@@ -24,7 +24,6 @@ import javax.inject.Singleton;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Uses SemVer implementation to increase major element when resolving the
release version.
@@ -37,13 +36,13 @@ class SemVerMajorReleaseVersionPolicy extends
AbstractSemVerVersionPolicy {
@Override
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request)
throws VersionParseException {
- Version version =
createVersionFromRequest(request).toReleaseVersion().next(Version.Element.MAJOR);
+ SemVer version =
createVersionFromRequest(request).toReleaseVersion().next(SemVer.Element.MAJOR);
return createResult(version);
}
@Override
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest
request) throws VersionParseException {
- Version version =
createVersionFromRequest(request).next(Version.Element.PATCH);
+ SemVer version =
createVersionFromRequest(request).next(SemVer.Element.PATCH);
return createSnapshotResult(version);
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorDevelopmentVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorDevelopmentVersionPolicy.java
index 573e6f99..0fa7d816 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorDevelopmentVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorDevelopmentVersionPolicy.java
@@ -24,7 +24,6 @@ import javax.inject.Singleton;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Uses SemVer implementation to increase minor element when resolving the
development version.
@@ -37,13 +36,13 @@ class SemVerMinorDevelopmentVersionPolicy extends
AbstractSemVerVersionPolicy {
@Override
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request)
throws VersionParseException {
- Version version = createVersionFromRequest(request).toReleaseVersion();
+ SemVer version = createVersionFromRequest(request).toReleaseVersion();
return createResult(version);
}
@Override
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest
request) throws VersionParseException {
- Version version =
createVersionFromRequest(request).next(Version.Element.MINOR);
+ SemVer version =
createVersionFromRequest(request).next(SemVer.Element.MINOR);
return createSnapshotResult(version);
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorReleaseVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorReleaseVersionPolicy.java
index 951c706a..66426d81 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorReleaseVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorReleaseVersionPolicy.java
@@ -24,7 +24,6 @@ import javax.inject.Singleton;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Uses SemVer implementation to increase minor element when resolving the
release version.
@@ -37,13 +36,13 @@ class SemVerMinorReleaseVersionPolicy extends
AbstractSemVerVersionPolicy {
@Override
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request)
throws VersionParseException {
- Version version =
createVersionFromRequest(request).toReleaseVersion().next(Version.Element.MINOR);
+ SemVer version =
createVersionFromRequest(request).toReleaseVersion().next(SemVer.Element.MINOR);
return createResult(version);
}
@Override
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest
request) throws VersionParseException {
- Version version =
createVersionFromRequest(request).next(Version.Element.PATCH);
+ SemVer version =
createVersionFromRequest(request).next(SemVer.Element.PATCH);
return createSnapshotResult(version);
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerPatchDevelopmentVersionPolicy.java
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerPatchDevelopmentVersionPolicy.java
index f0b8e75b..70cdd886 100644
---
a/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerPatchDevelopmentVersionPolicy.java
+++
b/maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerPatchDevelopmentVersionPolicy.java
@@ -24,7 +24,6 @@ import javax.inject.Singleton;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
import org.apache.maven.shared.release.versions.VersionParseException;
-import org.semver.Version;
/**
* Uses SemVer implementation to increase patch element when resolving the
development version.
@@ -37,13 +36,13 @@ class SemVerPatchDevelopmentVersionPolicy extends
AbstractSemVerVersionPolicy {
@Override
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request)
throws VersionParseException {
- Version version = createVersionFromRequest(request).toReleaseVersion();
+ SemVer version = createVersionFromRequest(request).toReleaseVersion();
return createResult(version);
}
@Override
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest
request) throws VersionParseException {
- Version version =
createVersionFromRequest(request).next(Version.Element.PATCH);
+ SemVer version =
createVersionFromRequest(request).next(SemVer.Element.PATCH);
return createSnapshotResult(version);
}
}
diff --git
a/maven-release-policies/maven-release-semver-policy/src/test/java/org/apache/maven/shared/release/policy/semver/SemVerTest.java
b/maven-release-policies/maven-release-semver-policy/src/test/java/org/apache/maven/shared/release/policy/semver/SemVerTest.java
new file mode 100644
index 00000000..8110052f
--- /dev/null
+++
b/maven-release-policies/maven-release-semver-policy/src/test/java/org/apache/maven/shared/release/policy/semver/SemVerTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.shared.release.policy.semver;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Unit tests for the SemVer class.
+ */
+class SemVerTest {
+
+ @ParameterizedTest
+ @CsvSource({
+ "'1.2.3', 1, 2, 3, , , '1.2.3'",
+ "'1.2.3-alpha.1', 1, 2, 3, 'alpha.1', , '1.2.3-alpha.1'",
+ "'1.2.3+build.123', 1, 2, 3, , 'build.123', '1.2.3+build.123'",
+ "'1.2.3-beta.2+build.456', 1, 2, 3, 'beta.2', 'build.456',
'1.2.3-beta.2+build.456'",
+ "'1.0.0-SNAPSHOT', 1, 0, 0, 'SNAPSHOT', , '1.0.0-SNAPSHOT'",
+ "' 1.2.3 ', 1, 2, 3, , , '1.2.3'",
+ "'0.0.0', 0, 0, 0, , , '0.0.0'",
+ "'123.456.789', 123, 456, 789, , , '123.456.789'"
+ })
+ void testParseVersion(
+ String version,
+ int expectedMajor,
+ int expectedMinor,
+ int expectedPatch,
+ String expectedPreRelease,
+ String expectedMetadata,
+ String expectedToString) {
+ SemVer semVer = SemVer.parse(version);
+ assertEquals(expectedMajor, semVer.getMajor());
+ assertEquals(expectedMinor, semVer.getMinor());
+ assertEquals(expectedPatch, semVer.getPatch());
+ assertEquals(expectedPreRelease, semVer.getPreRelease());
+ assertEquals(expectedMetadata, semVer.getMetadata());
+ assertEquals(expectedToString, semVer.toString());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"invalid", "1.2", "1.2.3.4", ""})
+ void testParseInvalidVersionThrowsException(String invalidVersion) {
+ assertThrows(IllegalArgumentException.class, () ->
SemVer.parse(invalidVersion));
+ }
+
+ @Test
+ void testParseNullVersionThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> SemVer.parse(null));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "'1.2.3-SNAPSHOT', '1.2.3'",
+ "'1.2.3-beta+build', '1.2.3'",
+ "'1.0.0-alpha', '1.0.0'",
+ "'2.1.5+metadata', '2.1.5'"
+ })
+ void testToReleaseVersion(String input, String expected) {
+ SemVer version = SemVer.parse(input);
+ SemVer releaseVersion = version.toReleaseVersion();
+ assertEquals(expected, releaseVersion.toString());
+ assertNull(releaseVersion.getPreRelease());
+ assertNull(releaseVersion.getMetadata());
+ }
+
+ @ParameterizedTest
+ @CsvSource({"MAJOR, '2.0.0', 2, 0, 0", "MINOR, '1.3.0', 1, 3, 0", "PATCH,
'1.2.4', 1, 2, 4"})
+ void testNext(
+ SemVer.Element element, String expectedVersion, int expectedMajor,
int expectedMinor, int expectedPatch) {
+ SemVer version = SemVer.parse("1.2.3");
+ SemVer next = version.next(element);
+ assertEquals(expectedVersion, next.toString());
+ assertEquals(expectedMajor, next.getMajor());
+ assertEquals(expectedMinor, next.getMinor());
+ assertEquals(expectedPatch, next.getPatch());
+ }
+
+ @Test
+ void testNextClearsPreReleaseAndMetadata() {
+ SemVer version = SemVer.parse("1.2.3-beta+build");
+ SemVer next = version.next(SemVer.Element.MINOR);
+ assertEquals("1.2.3", next.toString());
+ assertNull(next.getPreRelease());
+ assertNull(next.getMetadata());
+ }
+
+ @Test
+ void testNextWithNullElementThrowsException() {
+ SemVer version = SemVer.parse("1.2.3");
+ assertThrows(NullPointerException.class, () -> version.next(null));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "'1.2.3', '1.2.3-SNAPSHOT', 'SNAPSHOT', , false",
+ "'1.0.0', '1.0.0-SNAPSHOT', 'SNAPSHOT', , false",
+ "'1.2.3-beta.1', '1.2.3-SNAPSHOT', 'SNAPSHOT', , false",
+ "'1.2.3-SNAPSHOT', '1.2.3-SNAPSHOT', 'SNAPSHOT', , true"
+ })
+ void testToSnapshotVersion(
+ String input,
+ String expectedVersion,
+ String expectedPreRelease,
+ String expectedMetadata,
+ boolean shouldBeSameObject) {
+ SemVer version = SemVer.parse(input);
+ SemVer snapshotVersion = version.toSnapshotVersion();
+ assertEquals(expectedVersion, snapshotVersion.toString());
+ assertEquals(expectedPreRelease, snapshotVersion.getPreRelease());
+ assertEquals(expectedMetadata, snapshotVersion.getMetadata());
+
+ // For the already snapshot case, verify it returns the same object
+ if (shouldBeSameObject) {
+ assertSame(version, snapshotVersion);
+ }
+ }
+
+ @ParameterizedTest
+ @CsvSource({"-1, 0, 0", "0, -1, 0", "0, 0, -1"})
+ void testConstructorValidation(int major, int minor, int patch) {
+ assertThrows(IllegalArgumentException.class, () -> new SemVer(major,
minor, patch, null, null));
+ }
+}