From 5d0aa683cbde382de4d7dfa71657cd6fcd326f0f Mon Sep 17 00:00:00 2001 From: Zafar Khaja Date: Sun, 3 Mar 2013 23:13:48 +0400 Subject: [PATCH] Make major refactoring toward object-orientation --- pom.xml | 2 +- .../semver/AlphaNumericVersion.java | 120 +++++ .../zafarkhaja/semver/NormalVersion.java | 135 ++++++ .../com/github/zafarkhaja/semver/Version.java | 239 ++++------ .../semver/AlphaNumericVersionTest.java | 166 +++++++ .../zafarkhaja/semver/NormalVersionTest.java | 195 ++++++++ .../github/zafarkhaja/semver/VersionTest.java | 439 +++++++----------- 7 files changed, 886 insertions(+), 410 deletions(-) create mode 100644 src/main/java/com/github/zafarkhaja/semver/AlphaNumericVersion.java create mode 100644 src/main/java/com/github/zafarkhaja/semver/NormalVersion.java create mode 100644 src/test/java/com/github/zafarkhaja/semver/AlphaNumericVersionTest.java create mode 100644 src/test/java/com/github/zafarkhaja/semver/NormalVersionTest.java diff --git a/pom.xml b/pom.xml index 5f2e0d4..abccb5a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.zafarkhaja semver - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT jar semver diff --git a/src/main/java/com/github/zafarkhaja/semver/AlphaNumericVersion.java b/src/main/java/com/github/zafarkhaja/semver/AlphaNumericVersion.java new file mode 100644 index 0000000..b68acfc --- /dev/null +++ b/src/main/java/com/github/zafarkhaja/semver/AlphaNumericVersion.java @@ -0,0 +1,120 @@ +/* + * The MIT License + * + * Copyright 2013 Zafar Khaja . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.github.zafarkhaja.semver; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author Zafar Khaja + */ +class AlphaNumericVersion implements Comparable { + + static final String FORMAT = "([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)"; + private static final Pattern PATTERN = Pattern.compile("^" + FORMAT + "$"); + + private String value; + + AlphaNumericVersion(String value) { + if (value == null) { + throw new NullPointerException( + "Alpha-numeric version MUST NOT be NULL" + ); + } + Matcher matcher = PATTERN.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException( + "Alpha-numeric version MUST consist of dot separated identifiers [0-9A-Za-z-]" + ); + } + this.value = matcher.group(0); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof AlphaNumericVersion)) { + return false; + } + return compareTo((AlphaNumericVersion) other) == 0 ? true : false; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + return value; + } + + @Override + public int compareTo(AlphaNumericVersion other) { + String[] thisIds = value.split("\\."); + String[] otherIds = other.value.split("\\."); + + int result = compareIdentifierArrays(thisIds, otherIds); + if (result == 0) { + result = thisIds.length - otherIds.length; + } + return result; + } + + private int compareIdentifierArrays(String[] ids1, String[] ids2) { + int result = 0; + int length = getLeastCommonArrayLength(ids1, ids2); + for (int i = 0; i < length; i++) { + result = compareIdentifiers(ids1[i], ids2[i]); + if (result != 0) { + break; + } + } + return result; + } + + private int getLeastCommonArrayLength(String[] arr1, String[] arr2) { + return arr1.length <= arr2.length ? arr1.length : arr2.length; + } + + private int compareIdentifiers(String id1, String id2) { + if (isInt(id1) && isInt(id2)) { + return Integer.parseInt(id1) - Integer.parseInt(id2); + } else { + return id1.compareTo(id2); + } + } + + private boolean isInt(String str) { + try { + Integer.parseInt(str); + } catch (NumberFormatException e) { + return false; + } + return true; + } +} diff --git a/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java b/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java new file mode 100644 index 0000000..dda755d --- /dev/null +++ b/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java @@ -0,0 +1,135 @@ +/* + * The MIT License + * + * Copyright 2013 Zafar Khaja . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.github.zafarkhaja.semver; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author Zafar Khaja + */ +class NormalVersion implements Comparable { + + private int major; + private int minor; + private int patch; + + static final String FORMAT = "(\\d+)\\.(\\d+)\\.(\\d+)"; + private static final Pattern PATTERN = Pattern.compile("^" + FORMAT + "$"); + + NormalVersion(int major, int minor, int patch) { + if (major < 0 || minor < 0 || patch < 0) { + throw new IllegalArgumentException( + "Major, minor and patch versions MUST be non-negative integers." + ); + } + this.major = major; + this.minor = minor; + this.patch = patch; + } + + static NormalVersion valueOf(String value) { + Matcher matcher = PATTERN.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException("Illegal normal version format"); + } + return new NormalVersion( + Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)) + ); + } + + int getMajor() { + return major; + } + + int getMinor() { + return minor; + } + + int getPatch() { + return patch; + } + + void incrementMajor() { + major = major + 1; + minor = 0; + patch = 0; + } + + void incrementMinor() { + minor = minor + 1; + patch = 0; + } + + void incrementPatch() { + patch = patch + 1; + } + + @Override + public int compareTo(NormalVersion other) { + int result = major - other.major; + if (result == 0) { + result = minor - other.minor; + if (result == 0) { + result = patch - other.patch; + } + } + return result; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof NormalVersion)) { + return false; + } + return compareTo((NormalVersion) other) == 0 ? true : false; + } + + @Override + public int hashCode() { + int hash = 17; + hash = 31 * hash + major; + hash = 31 * hash + minor; + hash = 31 * hash + patch; + return hash; + } + + /** + * Returns the string representation of this normal version. + * + * A normal version number MUST take the form X.Y.Z where X, Y, and Z are + * non-negative integers. X is the major version, Y is the minor version, + * and Z is the patch version. (SemVer p.2) + */ + @Override + public String toString() { + return String.format("%d.%d.%d", major, minor, patch); + } +} diff --git a/src/main/java/com/github/zafarkhaja/semver/Version.java b/src/main/java/com/github/zafarkhaja/semver/Version.java index 537bac5..60dfd76 100644 --- a/src/main/java/com/github/zafarkhaja/semver/Version.java +++ b/src/main/java/com/github/zafarkhaja/semver/Version.java @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package com.github.zafarkhaja.semver; import java.util.regex.Matcher; @@ -33,78 +32,93 @@ import java.util.regex.Pattern; */ public class Version implements Comparable { - private String rawVersion; + private NormalVersion normal; + private AlphaNumericVersion preRelease; + private AlphaNumericVersion build; - private int majorVersion; - private int minorVersion; - private int patchVersion; + private static final String PRE_RELEASE_PREFIX = "-"; + private static final String BUILD_PREFIX = "+"; - private String preReleaseVersion; - private String buildVersion; + private static final Pattern SEMVER_PATTERN; - private static final String NORMAL_VERSION = - "((?\\d+)\\.(?\\d+)\\.(?\\d+))"; + static { + StringBuilder sb = new StringBuilder(); + + sb.append("^"); + sb.append(NormalVersion.FORMAT); + sb.append("(?:"); + sb.append(PRE_RELEASE_PREFIX); + sb.append(AlphaNumericVersion.FORMAT); + sb.append(")?"); + sb.append("(?:"); + sb.append("\\"); + sb.append(BUILD_PREFIX); + sb.append(AlphaNumericVersion.FORMAT); + sb.append(")?"); + sb.append("$"); + + SEMVER_PATTERN = Pattern.compile(sb.toString()); + } - private static final String PRE_RELEASE_VERSION = - "(?:-(?[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"; + Version( + NormalVersion normal, + AlphaNumericVersion preRelease, + AlphaNumericVersion build + ) { + this.normal = normal; + this.preRelease = preRelease; + this.build = build; + } - private static final String BUILD_VERSION = - "(?:\\+(?[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"; - - private static final Pattern SEMVER_PATTERN = Pattern.compile( - "^" + NORMAL_VERSION + PRE_RELEASE_VERSION + BUILD_VERSION + "$" - ); - - public Version(String version) { - Matcher matcher = SEMVER_PATTERN.matcher(version); + public static Version valueOf(String value) { + Matcher matcher = SEMVER_PATTERN.matcher(value); if (!matcher.matches()) { throw new IllegalArgumentException( "Illegal version format" ); } - rawVersion = version; - majorVersion = Integer.parseInt(matcher.group("major")); - minorVersion = Integer.parseInt(matcher.group("minor")); - patchVersion = Integer.parseInt(matcher.group("patch")); + NormalVersion normal = new NormalVersion( + Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)) + ); - preReleaseVersion = matcher.group("preRelease"); - buildVersion = matcher.group("build"); + AlphaNumericVersion preRelease = + (matcher.group(4) != null) ? + new AlphaNumericVersion(matcher.group(4)) : + null; + + AlphaNumericVersion build = + (matcher.group(5) != null) ? + new AlphaNumericVersion(matcher.group(5)) : + null; + + return new Version(normal, preRelease, build); } public int getMajorVersion() { - return majorVersion; + return normal.getMajor(); } public int getMinorVersion() { - return minorVersion; + return normal.getMinor(); } public int getPatchVersion() { - return patchVersion; + return normal.getPatch(); + } + + public String getNormalVersion() { + return normal.toString(); } public String getPreReleaseVersion() { - return preReleaseVersion; + return (preRelease != null) ? preRelease.toString() : ""; } public String getBuildVersion() { - return buildVersion; - } - - public void bumpMajorVersion() { - majorVersion = majorVersion + 1; - minorVersion = 0; - patchVersion = 0; - } - - public void bumpMinorVersion() { - minorVersion = minorVersion + 1; - patchVersion = 0; - } - - public void bumpPatchVersion() { - patchVersion = patchVersion + 1; + return (build != null) ? build.toString() : ""; } public boolean greaterThan(Version other) { @@ -126,9 +140,9 @@ public class Version implements Comparable { @Override public boolean equals(Object other) { if (this == other) { - return true; + return true; } - if (null == other || this.getClass() != other.getClass()) { + if (!(other instanceof Version)) { return false; } return compareTo((Version) other) == 0 ? true : false; @@ -137,128 +151,55 @@ public class Version implements Comparable { @Override public int hashCode() { int hash = 5; - hash = 97 * hash + majorVersion; - hash = 97 * hash + minorVersion; - hash = 97 * hash + patchVersion; - hash = 97 * hash + ( - preReleaseVersion != null ? preReleaseVersion.hashCode(): 0 - ); - hash = 97 * hash + ( - buildVersion != null ? buildVersion.hashCode() : 0 - ); + hash = 97 * hash + (normal != null ? normal.hashCode() : 0); + hash = 97 * hash + (preRelease != null ? preRelease.hashCode() : 0); + hash = 97 * hash + (build != null ? build.hashCode() : 0); return hash; } @Override public String toString() { - return rawVersion; + StringBuilder sb = new StringBuilder(getNormalVersion()); + if (preRelease != null) { + sb.append(PRE_RELEASE_PREFIX); + sb.append(getPreReleaseVersion()); + } + if (build != null) { + sb.append(BUILD_PREFIX); + sb.append(getBuildVersion()); + } + return sb.toString(); } @Override public int compareTo(Version other) { - int result = compareNormalVersions(other); + int result = normal.compareTo(other.normal); if (result == 0) { - result = comparePreReleaseVersions(other); - } - if (result == 0) { - result = compareBuildVersions(other); - } - return result; - } - - private int compareNormalVersions(Version other) { - int result = compareInts(majorVersion, other.getMajorVersion()); - if (result == 0) { - result = compareInts(minorVersion, other.getMinorVersion()); + result = comparePreReleases(other); if (result == 0) { - result = compareInts(patchVersion, other.getPatchVersion()); + result = compareBuilds(other); } } return result; } - private int compareInts(int thisOp, int otherOp) { - return (thisOp == otherOp) ? 0 : ((thisOp > otherOp) ? 1 : -1); - } - - private int comparePreReleaseVersions(Version other) { - if (preReleaseVersion == null ^ other.getPreReleaseVersion() == null) { - return preReleaseVersion == null ? 1 : -1; - } else { - return compareAlphaNumericVersions( - preReleaseVersion, - other.getPreReleaseVersion() - ); - } - } - - private int compareBuildVersions(Version other) { - if (buildVersion == null ^ other.getBuildVersion() == null) { - return buildVersion == null ? -1 : 1; - } else { - return compareAlphaNumericVersions( - buildVersion, - other.getBuildVersion() - ); - } - } - - private int compareAlphaNumericVersions(String thisOp, String otherOp) { - if (thisOp == null && otherOp == null) { - return 0; - } - String[] thisIdents = thisOp.split("\\."); - String[] otherIdents = otherOp.split("\\."); - - int result = compareIdentifierArrays(thisIdents, otherIdents); - if (result == 0 && thisIdents.length != otherIdents.length) { - result = (thisIdents.length > otherIdents.length) ? 1 : -1; - } - return result; - } - - private int compareIdentifierArrays(String[] thisArr, String[] otherArr) { + private int comparePreReleases(Version other) { int result = 0; - for (int i = 0; i < getSmallestArrayLength(thisArr, otherArr); i++) { - result = compareIdentifiers(thisArr[i], otherArr[i]); - if (result != 0) { - break; - } + if (preRelease != null && other.preRelease != null) { + result = preRelease.compareTo(other.preRelease); + } else if (preRelease == null ^ other.preRelease == null) { + result = preRelease == null ? 1 : -1; } return result; } - private int getSmallestArrayLength(String[] thisArr, String[] otherArr) { - if (thisArr.length <= otherArr.length) { - return thisArr.length; - } else { - return otherArr.length; + private int compareBuilds(Version other) { + int result = 0; + if (build != null && other.build != null) { + result = build.compareTo(other.build); + } else if (build == null ^ other.build == null) { + result = build == null ? -1 : 1; } - } - - private int compareIdentifiers(String thisIdent, String otherIdent) { - if (isInt(thisIdent) && isInt(otherIdent)) { - return compareInts( - Integer.parseInt(thisIdent), - Integer.parseInt(otherIdent) - ); - } else if (isInt(thisIdent) || isInt(otherIdent)) { - /** - * Numeric identifiers always have lower precedence - * than non-numeric identifiers. - */ - return isInt(thisIdent) ? -1 : 1; - } else { - return thisIdent.compareTo(otherIdent); - } - } - - private boolean isInt(String str) { - try { - Integer.parseInt(str); - } catch (NumberFormatException e) { - return false; - } - return true; + return result; } } diff --git a/src/test/java/com/github/zafarkhaja/semver/AlphaNumericVersionTest.java b/src/test/java/com/github/zafarkhaja/semver/AlphaNumericVersionTest.java new file mode 100644 index 0000000..b7afd4d --- /dev/null +++ b/src/test/java/com/github/zafarkhaja/semver/AlphaNumericVersionTest.java @@ -0,0 +1,166 @@ +/* + * The MIT License + * + * Copyright 2013 Zafar Khaja . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.github.zafarkhaja.semver; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; + +/** + * + * @author Zafar Khaja + */ +@RunWith(Enclosed.class) +public class AlphaNumericVersionTest { + + public static class CoreFunctionalityTest { + + @Test + public void mustConsistOfDotSeparatedIdentifiersOfAlphaNumericsAndHyphen() { + String[] invalidVersions = { + null, + "", + "123!", + "1a:2b:3c", + "123,abc,123", + }; + for (String ver : invalidVersions) { + try { + AlphaNumericVersion v = new AlphaNumericVersion(ver); + } catch (Exception e) { + continue; + } + fail("Alpha-numeric version MUST consist of dot separated identifiers [0-9A-Za-z-]"); + } + } + + @Test + public void mustCompareEachIdentifierSeparately() { + AlphaNumericVersion v1 = new AlphaNumericVersion("beta.2.abc"); + AlphaNumericVersion v2 = new AlphaNumericVersion("beta.1.edf"); + assertTrue(0 < v1.compareTo(v2)); + } + + @Test + public void shouldCompareIdentifiersCountIfCommonIdentifiersAreEqual() { + AlphaNumericVersion v1 = new AlphaNumericVersion("beta.abc"); + AlphaNumericVersion v2 = new AlphaNumericVersion("beta.abc.def"); + assertTrue(0 > v1.compareTo(v2)); + } + + @Test + public void shouldComapareDigitsOnlyIdentifiersNumerically() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.321"); + assertTrue(0 > v1.compareTo(v2)); + } + + @Test + public void shouldCompareMixedIdentifiersLexicallyInAsciiSortOrder() { + AlphaNumericVersion v1 = new AlphaNumericVersion("beta.abc"); + AlphaNumericVersion v2 = new AlphaNumericVersion("beta.111"); + assertTrue(0 < v1.compareTo(v2)); + } + + @Test + public void shouldOverrideEqualsMethod() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v3 = new AlphaNumericVersion("alpha.321"); + assertTrue(v1.equals(v2)); + assertFalse(v1.equals(v3)); + } + } + + public static class EqualsMethodTest { + + @Test + public void shouldBeReflexive() { + AlphaNumericVersion v = new AlphaNumericVersion("alpha.123"); + assertTrue(v.equals(v)); + } + + @Test + public void shouldBeSymmetric() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.123"); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v1)); + } + + @Test + public void shouldBeTransitive() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v3 = new AlphaNumericVersion("alpha.123"); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v3)); + assertTrue(v1.equals(v3)); + } + + @Test + public void shouldBeConsistent() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.123"); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { + AlphaNumericVersion v = new AlphaNumericVersion("alpha.123"); + assertFalse(v.equals(new String("alpha.123"))); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsNull() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = null; + assertFalse(v1.equals(v2)); + } + } + + public static class HashCodeMethodTest { + + @Test + public void shouldReturnSameHashCodeIfVersionsAreEqual() { + AlphaNumericVersion v1 = new AlphaNumericVersion("alpha.123"); + AlphaNumericVersion v2 = new AlphaNumericVersion("alpha.123"); + assertTrue(v1.equals(v2)); + assertEquals(v1.hashCode(), v2.hashCode()); + } + } + + public static class ToStringMethodTest { + + @Test + public void shouldReturnStringRepresentation() { + String value = "beta.abc.def"; + AlphaNumericVersion v = new AlphaNumericVersion(value); + assertEquals(value, v.toString()); + } + } +} diff --git a/src/test/java/com/github/zafarkhaja/semver/NormalVersionTest.java b/src/test/java/com/github/zafarkhaja/semver/NormalVersionTest.java new file mode 100644 index 0000000..4d4cbc0 --- /dev/null +++ b/src/test/java/com/github/zafarkhaja/semver/NormalVersionTest.java @@ -0,0 +1,195 @@ +/* + * The MIT License + * + * Copyright 2013 Zafar Khaja . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.github.zafarkhaja.semver; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; + +/** + * + * @author Zafar Khaja + */ +@RunWith(Enclosed.class) +public class NormalVersionTest { + + public static class CoreFunctionalityTest { + + @Test + public void mustConsistOfMajorMinorAndPatchVersions() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertEquals(1, v.getMajor()); + assertEquals(2, v.getMinor()); + assertEquals(3, v.getPatch()); + } + + @Test + public void mustTakeTheFormOfXDotYDotZWhereXyzAreNonNegativeIntegers() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertEquals("1.2.3", v.toString()); + } + + @Test + public void shouldAcceptOnlyNonNegativeMajorMinorAndPatchVersions() { + int[][] invalidVersions = {{-1, 2, 3}, {1, -2, 3}, {1, 2, -3}}; + for (int[] versionParts : invalidVersions) { + try { + NormalVersion v = new NormalVersion( + versionParts[0], + versionParts[1], + versionParts[2] + ); + } catch (IllegalArgumentException e) { + continue; + } + fail("Major, minor and patch versions MUST be non-negative integers."); + } + } + + @Test + public void mustIncreaseEachElementNumericallyByIncrementsOfOne() { + int major = 1, minor = 2, patch = 3; + NormalVersion v = new NormalVersion(major, minor, patch); + v.incrementPatch(); + assertEquals(patch + 1, v.getPatch()); + v.incrementMinor(); + assertEquals(minor + 1, v.getMinor()); + v.incrementMajor(); + assertEquals(major + 1, v.getMajor()); + } + + @Test + public void mustResetMinorAndPatchToZeroWhenMajorIsIncremented() { + NormalVersion v = new NormalVersion(1, 2, 3); + v.incrementMajor(); + assertEquals(2, v.getMajor()); + assertEquals(0, v.getMinor()); + assertEquals(0, v.getPatch()); + } + + @Test + public void mustResetPatchToZeroWhenMinorIsIncremented() { + NormalVersion v = new NormalVersion(1, 2, 3); + v.incrementMinor(); + assertEquals(1, v.getMajor()); + assertEquals(3, v.getMinor()); + assertEquals(0, v.getPatch()); + } + + @Test + public void mustCompareMajorMinorAndPatchNumerically() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertTrue(0 < v.compareTo(new NormalVersion(0, 2, 3))); + assertTrue(0 == v.compareTo(new NormalVersion(1, 2, 3))); + assertTrue(0 > v.compareTo(new NormalVersion(1, 2, 4))); + } + + @Test + public void shouldOverrideEqualsMethod() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = new NormalVersion(1, 2, 3); + NormalVersion v3 = new NormalVersion(3, 2, 1); + assertTrue(v1.equals(v2)); + assertFalse(v1.equals(v3)); + } + + @Test + public void shouldHaveStaticFactoryMethod() { + NormalVersion v = NormalVersion.valueOf("1.2.3"); + assertEquals(1, v.getMajor()); + assertEquals(2, v.getMinor()); + assertEquals(3, v.getPatch()); + } + } + + public static class EqualsMethodTest { + + @Test + public void shouldBeReflexive() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertTrue(v.equals(v)); + } + + @Test + public void shouldBeSymmetric() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = new NormalVersion(1, 2, 3); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v1)); + } + + @Test + public void shouldBeTransitive() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = new NormalVersion(1, 2, 3); + NormalVersion v3 = new NormalVersion(1, 2, 3); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v3)); + assertTrue(v1.equals(v3)); + } + + @Test + public void shouldBeConsistent() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = new NormalVersion(1, 2, 3); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertFalse(v.equals(new String("1.2.3"))); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsNull() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = null; + assertFalse(v1.equals(v2)); + } + } + + public static class HashCodeMethodTest { + + @Test + public void shouldReturnSameHashCodeIfVersionsAreEqual() { + NormalVersion v1 = new NormalVersion(1, 2, 3); + NormalVersion v2 = new NormalVersion(1, 2, 3); + assertTrue(v1.equals(v2)); + assertEquals(v1.hashCode(), v2.hashCode()); + } + } + + public static class ToStringMethodTest { + + @Test + public void shouldReturnStringRepresentation() { + NormalVersion v = new NormalVersion(1, 2, 3); + assertEquals("1.2.3", v.toString()); + } + } +} diff --git a/src/test/java/com/github/zafarkhaja/semver/VersionTest.java b/src/test/java/com/github/zafarkhaja/semver/VersionTest.java index fc34064..00bbf8c 100644 --- a/src/test/java/com/github/zafarkhaja/semver/VersionTest.java +++ b/src/test/java/com/github/zafarkhaja/semver/VersionTest.java @@ -21,285 +21,204 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package com.github.zafarkhaja.semver; import static org.junit.Assert.*; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; /** * * @author Zafar Khaja */ +@RunWith(Enclosed.class) public class VersionTest { - @Test public void - mustConsistOfMajorMinorAndPatchVersions() { - Version version = new Version("1.2.3"); - assertNotNull(version.getMajorVersion()); - assertNotNull(version.getMinorVersion()); - assertNotNull(version.getPatchVersion()); - } - - @Test public void - mustTakeTheFormOfXDotYDotZWhereXyzAreNonNegativeIntegers() { - Version version = new Version("1.2.3"); - assertEquals(1, version.getMajorVersion()); - assertEquals(2, version.getMinorVersion()); - assertEquals(3, version.getPatchVersion()); - } - - @Test public void - shouldAcceptOnlyNonNegativeMajorMinorAndPatchVersions() { - String[] versionStrings = {"-1.2.3", "1.-2.3", "1.2.-3"}; - for (String illegalVersion : versionStrings) { - try { - Version version = new Version(illegalVersion); - } catch (IllegalArgumentException e) { - continue; + public static class CoreFunctionalityTest { + + @Test + public void mayHavePreReleaseFollowingPatchAppendedWithHyphen() { + Version v = Version.valueOf("1.2.3-alpha"); + assertEquals("alpha", v.getPreReleaseVersion()); + } + + @Test + public void preReleaseShouldHaveLowerPrecedenceThanAssociatedNormal() { + Version v1 = Version.valueOf("1.3.7"); + Version v2 = Version.valueOf("1.3.7-alpha"); + assertTrue(0 < v1.compareTo(v2)); + assertTrue(0 > v2.compareTo(v1)); + } + + @Test + public void mayHaveBuildFollowingPatchOrPreReleaseAppendedWithPlus() { + Version v = Version.valueOf("1.2.3+build"); + assertEquals("build", v.getBuildVersion()); + } + + @Test + public void shouldCompareBuildIfNormalAndPreReleaseAreEqual() { + Version v1 = Version.valueOf("1.3.7-beta+build.1"); + Version v2 = Version.valueOf("1.3.7-beta+build.2"); + assertTrue(0 > v1.compareTo(v2)); + } + + @Test + public void buildShouldHaveHigherPrecedenceThanAssociatedNormal() { + Version v1 = Version.valueOf("1.3.7"); + Version v2 = Version.valueOf("1.3.7+build"); + assertTrue(0 > v1.compareTo(v2)); + assertTrue(0 < v2.compareTo(v1)); + } + + @Test + public void shouldHaveGreaterThanMethodReturningBoolean() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("1.3.7"); + assertTrue(v1.greaterThan(v2)); + assertFalse(v2.greaterThan(v1)); + assertFalse(v1.greaterThan(v1)); + } + + @Test + public void shouldHaveGreaterThanOrEqualsToMethodReturningBoolean() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("1.3.7"); + assertTrue(v1.greaterThanOrEqualsTo(v2)); + assertFalse(v2.greaterThanOrEqualsTo(v1)); + assertTrue(v1.greaterThanOrEqualsTo(v1)); + } + + @Test + public void shouldHaveLessThanMethodReturningBoolean() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("1.3.7"); + assertFalse(v1.lessThan(v2)); + assertTrue(v2.lessThan(v1)); + assertFalse(v1.lessThan(v1)); + } + + @Test + public void shouldHaveLessThanOrEqualsToMethodReturningBoolean() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("1.3.7"); + assertFalse(v1.lessThanOrEqualsTo(v2)); + assertTrue(v2.lessThanOrEqualsTo(v1)); + assertTrue(v1.lessThanOrEqualsTo(v1)); + } + + @Test + public void shouldOverrideEqualsMethod() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("2.3.7"); + Version v3 = Version.valueOf("1.3.7"); + assertTrue(v1.equals(v1)); + assertTrue(v1.equals(v2)); + assertFalse(v1.equals(v3)); + } + + @Test + public void shouldCorrectlyCompareAllVersionsFromSpecification() { + String[] versions = { + "1.0.0-alpha", + "1.0.0-alpha.1", + "1.0.0-beta.2", + "1.0.0-beta.11", + "1.0.0-rc.1", + "1.0.0-rc.1+build.1", + "1.0.0", + "1.0.0+0.3.7", + "1.3.7+build", + "1.3.7+build.2.b8f12d7", + "1.3.7+build.11.e0f985a" + }; + for (int i = 1; i < versions.length; i++) { + Version v1 = Version.valueOf(versions[i-1]); + Version v2 = Version.valueOf(versions[i]); + assertTrue(v1.lessThan(v2)); } - fail("An expected exception has not been thrown."); + } + + @Test + public void shouldHaveStaticFactoryMethod() { + Version v = Version.valueOf("1.0.0-rc.1+build.1"); + assertEquals(1, v.getMajorVersion()); + assertEquals(0, v.getMinorVersion()); + assertEquals(0, v.getPatchVersion()); + assertEquals("1.0.0", v.getNormalVersion()); + assertEquals("rc.1", v.getPreReleaseVersion()); + assertEquals("build.1", v.getBuildVersion()); } } - @Test public void - mustIncreaseEachElementNumericallyByIncrementsOfOne() { - Version version = new Version("1.2.3"); - version.bumpPatchVersion(); - assertEquals(4, version.getPatchVersion()); - version.bumpMinorVersion(); - assertEquals(3, version.getMinorVersion()); - version.bumpMajorVersion(); - assertEquals(2, version.getMajorVersion()); + public static class EqualsMethodTest { + + @Test + public void shouldBeReflexive() { + Version v1 = Version.valueOf("2.3.7"); + assertTrue(v1.equals(v1)); + } + + @Test + public void shouldBeSymmetric() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("2.3.7"); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v1)); + } + + @Test + public void shouldBeTransitive() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("2.3.7"); + Version v3 = Version.valueOf("2.3.7"); + assertTrue(v1.equals(v2)); + assertTrue(v2.equals(v3)); + assertTrue(v1.equals(v3)); + } + + @Test + public void shouldBeConsistent() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("2.3.7"); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + assertTrue(v1.equals(v2)); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { + Version v1 = Version.valueOf("2.3.7"); + assertFalse(v1.equals(new String("2.3.7"))); + } + + @Test + public void shouldReturnFalseIfOtherVersionIsNull() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = null; + assertFalse(v1.equals(v2)); + } } - @Test public void - mustResetToZeroMinorAndPatchVersionsWhenMajorVersionIsIncremented() { - Version version = new Version("1.2.3"); - version.bumpMajorVersion(); - assertEquals(2, version.getMajorVersion()); - assertEquals(0, version.getMinorVersion()); - assertEquals(0, version.getPatchVersion()); + public static class HashCodeMethodTest { + + @Test + public void shouldReturnSameHashCodeIfVersionsAreEqual() { + Version v1 = Version.valueOf("2.3.7"); + Version v2 = Version.valueOf("2.3.7"); + assertTrue(v1.equals(v2)); + assertEquals(v1.hashCode(), v2.hashCode()); + } } - @Test public void - mustResetToZeroPatchVersionWhenMinorVersionIsIncremented() { - Version version = new Version("1.2.3"); - version.bumpMinorVersion(); - assertEquals(1, version.getMajorVersion()); - assertEquals(3, version.getMinorVersion()); - assertEquals(0, version.getPatchVersion()); - } - - @Test public void - mayHavePreReleaseVersionFollowingPatchVersionAppendedWithDash() { - Version version = new Version("1.2.3-alpha"); - assertEquals("alpha", version.getPreReleaseVersion()); - } - - @Test public void - preReleaseVersionMustCompriseDotSeparatedIdentifiersOfAlphaNumericsAndDash() { - Version version = new Version("1.0.0-x.7.z.92"); - assertEquals("x.7.z.92", version.getPreReleaseVersion()); - } - - @Test public void - mayHaveBuildVersionFollowingPatchOrPreReleaseVersionsAppendedWithPlus() { - Version version = new Version("1.2.3+build"); - assertEquals("build", version.getBuildVersion()); - } - - @Test public void - buildVersionMustCompriseDotSeparatedIdentifiersOfAlphaNumericsAndDash() { - Version version = new Version("1.3.7+build.11.e0f985a"); - assertEquals("build.11.e0f985a", version.getBuildVersion()); - } - - @Test public void - mustCompareMajorMinorAndPatchVersionsNumerically() { - Version version = new Version("1.2.3"); - assertEquals(1, version.compareTo(new Version("0.2.3"))); - assertEquals(0, version.compareTo(new Version("1.2.3"))); - assertEquals(-1, version.compareTo(new Version("1.2.4"))); - } - - @Test public void - mustComparePreReleaseAndBuildVersionsByComparingEachIdentifierSeparately() { - Version version1 = new Version("1.3.7+build.2.b8f12d7"); - Version version2 = new Version("1.3.7+build.11.e0f985a"); - assertEquals(-1, version1.compareTo(version2)); - } - - @Test public void - shouldComparePreReleaseVersionsIfNormalVersionsAreEqual() { - Version version1 = new Version("1.3.7-beta"); - Version version2 = new Version("1.3.7-alpha"); - assertEquals(1, version1.compareTo(version2)); - } - - @Test public void - preReleaseVersionShouldHaveLowerPrecedenceThanAssociatedNormalVersion() { - Version version1 = new Version("1.3.7"); - Version version2 = new Version("1.3.7-alpha"); - assertEquals(1, version1.compareTo(version2)); - assertEquals(-1, version2.compareTo(version1)); - } - - @Test public void - shouldCompareBuildVersionsIfNormalAndPreReleaseVersionsAreEqual() { - Version version1 = new Version("1.3.7-beta+build.1"); - Version version2 = new Version("1.3.7-beta+build.2"); - assertEquals(-1, version1.compareTo(version2)); - } - - @Test public void - buildVersionShouldHaveHigherPrecedenceThanAssociatedNormalVersion() { - Version version1 = new Version("1.3.7"); - Version version2 = new Version("1.3.7+build"); - assertEquals(-1, version1.compareTo(version2)); - assertEquals(1, version2.compareTo(version1)); - } - - @Test public void - shouldCompareAccordingToIdentifiersCountIfCommonIdentifiersAreEqual() { - Version version1 = new Version("1.3.7-beta+build.3"); - Version version2 = new Version("1.3.7-beta+build"); - assertEquals(1, version1.compareTo(version2)); - } - - @Test public void - numericIdentifiersShouldHaveLowerPrecedenceThanNonNumericIdentfiers() { - Version version1 = new Version("1.3.7-beta+build.3"); - Version version2 = new Version("1.3.7-beta+build.a"); - assertEquals(-1, version1.compareTo(version2)); - } - - @Test public void - shouldHaveGreaterThanConvenienceMethodReturningBoolean() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("1.3.7"); - assertTrue(version1.greaterThan(version2)); - assertFalse(version2.greaterThan(version1)); - assertFalse(version1.greaterThan(version1)); - } - - @Test public void - shouldHaveGreaterThanOrEqualsToConvenienceMethodReturningBoolean() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("1.3.7"); - assertTrue(version1.greaterThanOrEqualsTo(version2)); - assertFalse(version2.greaterThanOrEqualsTo(version1)); - assertTrue(version1.greaterThanOrEqualsTo(version1)); - } - - @Test public void - shouldHaveLessThanConvenienceMethodReturningBoolean() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("1.3.7"); - assertFalse(version1.lessThan(version2)); - assertTrue(version2.lessThan(version1)); - assertFalse(version1.lessThan(version1)); - } - - @Test public void - shouldHaveLessThanOrEqualsToConvenienceMethodReturningBoolean() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("1.3.7"); - assertFalse(version1.lessThanOrEqualsTo(version2)); - assertTrue(version2.lessThanOrEqualsTo(version1)); - assertTrue(version1.lessThanOrEqualsTo(version1)); - } - - @Test public void - shouldOverrideEqualsMethodForConvenience() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("2.3.7"); - Version version3 = new Version("1.3.7"); - assertTrue(version1.equals(version1)); - assertTrue(version1.equals(version2)); - assertFalse(version1.equals(version3)); - } - - @Test public void - equalsMethodShouldBeReflexive() { - Version version1 = new Version("2.3.7"); - assertTrue(version1.equals(version1)); - } - - @Test public void - equalsMethodShouldBeSymmetric() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("2.3.7"); - assertTrue(version1.equals(version2)); - assertTrue(version2.equals(version1)); - } - - @Test public void - equalsMethodShouldBeTransitive() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("2.3.7"); - Version version3 = new Version("2.3.7"); - assertTrue(version1.equals(version2)); - assertTrue(version2.equals(version3)); - assertTrue(version1.equals(version3)); - } - - @Test public void - equalsMethodShouldBeConsistent() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("2.3.7"); - assertTrue(version1.equals(version2)); - assertTrue(version1.equals(version2)); - assertTrue(version1.equals(version2)); - } - - @Test public void - equalsMethodShouldReturnFalseIfOtherVersionIsNotInstanceOfVersion() { - Version version1 = new Version("2.3.7"); - assertFalse(version1.equals(new String("2.3.7"))); - } - - @Test public void - equalsMethodShouldReturnFalseIfOtherVersionIsNull() { - Version version1 = new Version("2.3.7"); - Version version2 = null; - assertFalse(version1.equals(version2)); - } - - @Test public void - hashCodeMethodShouldReturnSameHashCodeIfVersionsAreEqual() { - Version version1 = new Version("2.3.7"); - Version version2 = new Version("2.3.7"); - assertTrue(version1.equals(version2)); - assertEquals(version1.hashCode(), version2.hashCode()); - } - - @Test public void - shouldOverrideToStringMethod() { - String versionString = "1.2.3-beta+build"; - Version version = new Version(versionString); - assertEquals(versionString, version.toString()); - } - - @Test public void - shouldCorrectlyCompareAllVersionsFromSpecification() { - String[] versionStrings = { - "1.0.0-alpha", - "1.0.0-alpha.1", - "1.0.0-beta.2", - "1.0.0-beta.11", - "1.0.0-rc.1", - "1.0.0-rc.1+build.1", - "1.0.0", - "1.0.0+0.3.7", - "1.3.7+build", - "1.3.7+build.2.b8f12d7", - "1.3.7+build.11.e0f985a" - }; - for (int i = 1; i < versionStrings.length; i++) { - Version version1 = new Version(versionStrings[i-1]); - Version version2 = new Version(versionStrings[i]); - assertTrue(version1.lessThan(version2)); + public static class ToStringMethodTest { + + @Test + public void shouldReturnStringRepresentation() { + String value = "1.2.3-beta+build"; + Version v = Version.valueOf(value); + assertEquals(value, v.toString()); } } }