Added exceptions for minor version number. A single major version number can be parsed, but will not be output in toString().

master
nathan 2020-08-06 15:09:23 +02:00
parent 561f050df1
commit e1a8278cd5
4 changed files with 82 additions and 12 deletions

View File

@ -45,6 +45,7 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
* The minor version number.
*/
private final long minor;
protected final boolean minorSpecified;
/**
* The patch version number.
@ -52,6 +53,18 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
private final long patch;
protected final boolean patchSpecified;
/**
* Constructs a {@code NormalVersion} with the
* major version number.
*
* @param major the major version number
*
* @throws IllegalArgumentException if one of the version numbers is a negative integer
*/
NormalVersion(long major) {
this(major, 0, 0, false, false);
}
/**
* Constructs a {@code NormalVersion} with the
* major and minor version numbers.
@ -62,7 +75,7 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
* @throws IllegalArgumentException if one of the version numbers is a negative integer
*/
NormalVersion(long major, long minor) {
this(major, minor, 0, false);
this(major, minor, 0, true, false);
}
/**
@ -76,7 +89,7 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
* @throws IllegalArgumentException if one of the version numbers is a negative integer
*/
NormalVersion(long major, long minor, long patch) {
this(major, minor, patch, true);
this(major, minor, patch, true, true);
}
/**
@ -86,12 +99,13 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
* @param major the major version number
* @param minor the minor version number
* @param patch the patch version number
* @param minorSpecified true if the minor version number was specified
* @param patchSpecified true if the patch version number was specified
*
* @throws IllegalArgumentException if one of the version numbers is a negative integer
*/
private
NormalVersion(long major, long minor, long patch, boolean patchSpecified) {
NormalVersion(long major, long minor, long patch, boolean minorSpecified, boolean patchSpecified) {
if (major < 0 || minor < 0 || patch < 0) {
throw new IllegalArgumentException("Major, minor and patch versions MUST be non-negative integers.");
}
@ -99,6 +113,7 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
this.major = major;
this.minor = minor;
this.patch = patch;
this.minorSpecified = minorSpecified;
this.patchSpecified = patchSpecified;
}
@ -210,28 +225,36 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
/**
* Increments the major version number.
*
* 1.2.3 -> 1.2
* 1 -> 1.0
*
* @return a new instance of the {@code NormalVersion} class
*/
NormalVersion incrementMajor() {
return new NormalVersion(major + 1, 0, 0, false);
return new NormalVersion(major + 1, 0, 0, true, false);
}
/**
* Increments the minor version number.
*
* 1.2.3 -> 1.3
* 1.2 -> 1.3
*
* @return a new instance of the {@code NormalVersion} class
*/
NormalVersion incrementMinor() {
return new NormalVersion(major, minor + 1, 0, false);
return new NormalVersion(major, minor + 1, 0, false, false);
}
/**
* Increments the patch version number.
*
* 1.2.3 -> 1.2.4
*
* @return a new instance of the {@code NormalVersion} class
*/
NormalVersion incrementPatch() {
return new NormalVersion(major, minor, patch + 1, true);
return new NormalVersion(major, minor, patch + 1, true, true);
}
/**
@ -246,7 +269,10 @@ class NormalVersion implements Comparable<NormalVersion>, Serializable {
@Override
public
String toString() {
if (!patchSpecified && patch == 0) {
if (!minorSpecified && !patchSpecified && minor == 0 && patch == 0) {
return String.format("%d", major);
}
else if (!patchSpecified && patch == 0) {
return String.format("%d.%d", major, minor);
}
else {

View File

@ -29,6 +29,7 @@ import static com.dorkbox.version.VersionParser.CharType.EOI;
import static com.dorkbox.version.VersionParser.CharType.HYPHEN;
import static com.dorkbox.version.VersionParser.CharType.LETTER;
import static com.dorkbox.version.VersionParser.CharType.PLUS;
import static com.dorkbox.version.VersionParser.CharType.SPACE;
import java.util.ArrayList;
import java.util.EnumSet;
@ -84,6 +85,23 @@ class VersionParser implements Parser<Version> {
}
return (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z');
}
}, SPACE {
/**
* Checks if the specified element matches this type.
*
* @param chr the element to be tested
*
* @return {@code true} if the element matches this type
* or {@code false} otherwise
*/
@Override
public
boolean isMatchedBy(Character chr) {
if (chr == null) {
return false;
}
return chr == ' ';
}
}, DOT {
/**
* Checks if the specified element matches this type.
@ -556,11 +574,10 @@ class VersionParser implements Parser<Version> {
MetadataVersion preRelease = MetadataVersion.NULL;
MetadataVersion build = MetadataVersion.NULL;
// if we have no patch information, then we have an EXCEPTION to SemVer
if (!normal.patchSpecified) {
// EXCEPTION TO SEMVER
// EXCEPTION to SemVer??
if (!(normal.minorSpecified && normal.patchSpecified)) {
if (checkNextCharacter(LETTER, DIGIT)) {
// NOTE: build INSTEAD OF patch is not valid for semver, however when parsing we want to ALLOW parsing as much.
// NOTE: build INSTEAD OF minor/patch is not valid for semver, however when parsing we want to ALLOW parsing as much.
// straight away to 4.1.Final
// this is not valid semver, but we want to parse it anyways.
// when writing this information, IT WILL NOT be in the format, as it will follow semver.
@ -569,6 +586,11 @@ class VersionParser implements Parser<Version> {
// we can have other info.
if (!checkNextCharacter(HYPHEN, PLUS, EOI)) {
if (!normal.minorSpecified && checkNextCharacter(SPACE)) {
// fail. but we want to be specific with the error
consumeNextCharacter(DOT);
}
// fail. but we want to be specific with the error
consumeNextCharacter(DIGIT);
}
@ -585,6 +607,11 @@ class VersionParser implements Parser<Version> {
build = parseBuild();
}
if (checkNextCharacter(SPACE)) {
// fail. but we want to be specific with the error
consumeNextCharacter(DIGIT);
}
Character next = consumeNextCharacter(HYPHEN, PLUS, EOI);
if (HYPHEN.isMatchedBy(next)) {
preRelease = parsePreRelease();
@ -604,6 +631,7 @@ class VersionParser implements Parser<Version> {
*
* <pre>
* {@literal
* <version core> ::= <major>
* <version core> ::= <major> "." <minor>
* <version core> ::= <major> "." <minor> "." <patch>
* <version core> ::= <major> "." <minor> "." <build>
@ -615,6 +643,11 @@ class VersionParser implements Parser<Version> {
private
NormalVersion parseVersionCore() {
long major = Long.parseLong(numericIdentifier());
if (!checkNextCharacter(DOT)) {
// only major!
return new NormalVersion(major);
}
consumeNextCharacter(DOT);
long minor = Long.parseLong(numericIdentifier());

View File

@ -54,7 +54,8 @@ class ParserErrorHandlingTest {
public static
Collection<Object[]> parameters() {
return Arrays.asList(new Object[][] {
{"1", null, 1, new CharType[] {DOT}},
// {"1", null, 1, new CharType[] {DOT}}, // exception to semver, is that '1' is permitted (ie: leaving out the minor number)
{"1.FINAL", 'F', 2, new CharType[] {DIGIT}}, // double check for exception to SEMVER
{"1 ", ' ', 1, new CharType[] {DOT}},
{"1.", null, 2, new CharType[] {DIGIT}},
// {"1.2", null, 3, new CharType[] {DOT}}, // exception to semver, is that 1.2 is permitted (ie: leaving out the patch number)

View File

@ -52,6 +52,16 @@ class VersionTest {
public static
class CoreFunctionalityTest {
// MODIFY TEST
@Test
public
void onlyMajor() {
// not valid, but we should STILL be able to parse it (we just cannot write it).
Version v = Version.from("20180813");
assertEquals(20180813, v.getMajorVersion());
assertEquals(0, v.getMinorVersion());
}
// MODIFY TEST
@Test
public