From 2128942b95031180c9fab063fb43b8a710d1cdfe Mon Sep 17 00:00:00 2001 From: liamfallon Date: Thu, 4 Apr 2019 13:26:58 +0000 Subject: Add semantic version comparable class Class written by Jim Hahn that implements Comparable for comparing semantic versions. Lifted from policy models pap. Issue-ID: POLICY-1095 Change-Id: Ie8c5f9066c06cb569085e1390b3de3e4aa580267 Signed-off-by: liamfallon --- utils/pom.xml | 8 +- .../policy/common/utils/validation/Version.java | 113 ++++++++++++++++ .../common/utils/validation/VersionTest.java | 142 +++++++++++++++++++++ 3 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 utils/src/main/java/org/onap/policy/common/utils/validation/Version.java create mode 100644 utils/src/test/java/org/onap/policy/common/utils/validation/VersionTest.java diff --git a/utils/pom.xml b/utils/pom.xml index f75a60b8..15c00124 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -18,7 +18,8 @@ ============LICENSE_END========================================================= --> - + 4.0.0 @@ -63,6 +64,11 @@ org.eclipse.persistence javax.persistence + + org.projectlombok + lombok + provided + org.slf4j slf4j-api diff --git a/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java b/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java new file mode 100644 index 00000000..b5769948 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP COMMON + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.validation; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Version of an object within the model. Versions are assumed to be of the form: major or + * major.minor.patch, where each component is numeric. + */ +@Data +@RequiredArgsConstructor +@NoArgsConstructor(force = true) +public class Version implements Comparable { + private static final Logger logger = LoggerFactory.getLogger(Version.class); + + /** + * Pattern to match a version of the form, major or major.minor.patch, where all + * components are numeric. + */ + private static final Pattern VERSION_PAT = Pattern.compile("(\\d+)([.](\\d+)[.](\\d+))?"); + + private final int major; + private final int minor; + private final int patch; + + + /** + * Creates a version object. + * + * @param type type of object with which the version is associated, used when logging + * @param name name with which the version is associated, used when logging + * @param versionText the version, in textual form + * @return a new version, or {@code null} if the version cannot be created from the + * key (e.g., the key has a version that does not match the major.minor.patch + * form) + */ + public static Version makeVersion(String type, String name, String versionText) { + Matcher matcher = VERSION_PAT.matcher(versionText); + if (!matcher.matches()) { + logger.info("invalid version for {} {}: {}", type, name, versionText); + return null; + } + + try { + if (matcher.group(2) == null) { + // form: major + return new Version(Integer.parseInt(matcher.group(1)), 0, 0); + + } else { + // form: major.minor.patch + return new Version(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(3)), + Integer.parseInt(matcher.group(4))); + } + + } catch (NumberFormatException e) { + logger.info("invalid version for {} {}: {}", type, name, versionText, e); + return null; + } + } + + /** + * Generates a new version from the current version. + * + * @return a new version, of the form major.0.0, where "major" is one more than "this" + * version's major number + */ + public Version newVersion() { + return new Version(major + 1, 0, 0); + } + + @Override + public int compareTo(Version other) { + int result = Integer.compare(major, other.major); + if (result != 0) { + return result; + } + if ((result = Integer.compare(minor, other.minor)) != 0) { + return result; + } + return Integer.compare(patch, other.patch); + } + + @Override + public String toString() { + return major + "." + minor + "." + patch; + } +} \ No newline at end of file diff --git a/utils/src/test/java/org/onap/policy/common/utils/validation/VersionTest.java b/utils/src/test/java/org/onap/policy/common/utils/validation/VersionTest.java new file mode 100644 index 00000000..1a45f9e1 --- /dev/null +++ b/utils/src/test/java/org/onap/policy/common/utils/validation/VersionTest.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.validation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; + +public class VersionTest { + private static final String TYPE = "my-type"; + private static final String NAME = "my-name"; + + private static final int MAJOR = 10; + private static final int MINOR = 2; + private static final int PATCH = 3; + + private Version vers; + + @Before + public void setUp() { + vers = new Version(MAJOR, MINOR, PATCH); + } + + @Test + public void testHashCode() { + int hash = vers.hashCode(); + int hash2 = new Version(MAJOR, MINOR, PATCH + 1).hashCode(); + assertTrue(hash != hash2); + } + + @Test + public void testMakeVersion() { + assertEquals("9.8.7", Version.makeVersion(TYPE, NAME, "9.8.7").toString()); + assertEquals("9.0.0", Version.makeVersion(TYPE, NAME, "9").toString()); + + assertNull(Version.makeVersion(TYPE, NAME, "")); + assertNull(Version.makeVersion(TYPE, NAME, "a.3.4")); + assertNull(Version.makeVersion(TYPE, NAME, "100.")); + assertNull(Version.makeVersion(TYPE, NAME, "10000000000000000.2.3")); + assertNull(Version.makeVersion(TYPE, NAME, "1.20000000000000000.3")); + assertNull(Version.makeVersion(TYPE, NAME, "1.2.30000000000000000")); + } + + @Test + public void testNewVersion() { + vers = vers.newVersion(); + assertEquals("11.0.0", vers.toString()); + } + + @Test + public void testEquals() { + assertFalse(vers.equals(null)); + assertFalse(vers.equals(new Object())); + + assertTrue(vers.equals(vers)); + + assertTrue(vers.equals(new Version(MAJOR, MINOR, PATCH))); + + assertFalse(vers.equals(new Version(MAJOR + 1, MINOR, PATCH))); + assertFalse(vers.equals(new Version(MAJOR, MINOR + 1, PATCH))); + assertFalse(vers.equals(new Version(MAJOR, MINOR, PATCH + 1))); + } + + @Test + public void testCompareTo() { + vers = new Version(101, 201, 301); + + // equals case + assertTrue(new Version(101, 201, 301).compareTo(vers) == 0); + + // major takes precedence + assertTrue(new Version(102, 200, 300).compareTo(vers) > 0); + + // minor takes precedence over patch + assertTrue(new Version(101, 202, 300).compareTo(vers) > 0); + + // compare major + assertTrue(new Version(100, 201, 301).compareTo(vers) < 0); + assertTrue(new Version(102, 201, 301).compareTo(vers) > 0); + + // compare minor + assertTrue(new Version(101, 200, 301).compareTo(vers) < 0); + assertTrue(new Version(101, 202, 301).compareTo(vers) > 0); + + // compare patch + assertTrue(new Version(101, 201, 300).compareTo(vers) < 0); + assertTrue(new Version(101, 201, 302).compareTo(vers) > 0); + } + + @Test + public void testToString() { + assertEquals("10.2.3", vers.toString()); + } + + @Test + public void testGetMajor() { + assertEquals(MAJOR, vers.getMajor()); + } + + @Test + public void testGetMinor() { + assertEquals(MINOR, vers.getMinor()); + } + + @Test + public void testGetPatch() { + assertEquals(PATCH, vers.getPatch()); + } + + @Test + public void testVersionIntIntInt() { + assertEquals("5.6.7", new Version(5, 6, 7).toString()); + } + + @Test + public void testVersion() { + assertEquals("0.0.0", new Version().toString()); + } +} \ No newline at end of file -- cgit 1.2.3-korg