diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/LoggedExec.java b/buildSrc/src/main/groovy/org/elasticsearch/gradle/LoggedExec.java deleted file mode 100644 index 7f51c4fb3987d..0000000000000 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/LoggedExec.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.elasticsearch.gradle; - -import groovy.lang.Closure; -import org.gradle.api.GradleException; -import org.gradle.api.Task; -import org.gradle.api.tasks.Exec; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.stream.Collectors; - -/** - * A wrapper around gradle's Exec task to capture output and log on error. - */ -public class LoggedExec extends Exec { - - protected ByteArrayOutputStream output = new ByteArrayOutputStream(); - - public LoggedExec() { - if (getLogger().isInfoEnabled() == false) { - setStandardOutput(output); - setErrorOutput(output); - setIgnoreExitValue(true); - doLast(new Closure(this, this) { - public void doCall(Task it) throws IOException { - if (getExecResult().getExitValue() != 0) { - for (String line : output.toString("UTF-8").split("\\R")) { - getLogger().error(line); - } - throw new GradleException( - "Process \'" + getExecutable() + " " + - getArgs().stream().collect(Collectors.joining(" "))+ - "\' finished with non-zero exit value " + - String.valueOf(getExecResult().getExitValue()) - ); - } - } - }); - } - } -} diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/Version.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/Version.groovy deleted file mode 100644 index c28738d7695eb..0000000000000 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/Version.groovy +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.gradle - -import groovy.transform.Sortable -import java.util.regex.Matcher -import org.gradle.api.InvalidUserDataException - -/** - * Encapsulates comparison and printing logic for an x.y.z version. - */ -@Sortable(includes=['id']) -public class Version { - - final int major - final int minor - final int revision - final int id - final boolean snapshot - /** - * Suffix on the version name. - */ - final String suffix - - public Version(int major, int minor, int revision, - String suffix, boolean snapshot) { - this.major = major - this.minor = minor - this.revision = revision - this.snapshot = snapshot - this.suffix = suffix - - int suffixOffset = 0 - if (suffix.contains("alpha")) { - suffixOffset += Integer.parseInt(suffix.substring(6)) - } else if (suffix.contains("beta")) { - suffixOffset += 25 + Integer.parseInt(suffix.substring(5)) - } else if (suffix.contains("rc")) { - suffixOffset += 50 + Integer.parseInt(suffix.substring(3)); - } - - this.id = major * 1000000 + minor * 10000 + revision * 100 + suffixOffset - } - - public static Version fromString(String s) { - Matcher m = s =~ /(\d+)\.(\d+)\.(\d+)(-alpha\d+|-beta\d+|-rc\d+)?(-SNAPSHOT)?/ - if (m.matches() == false) { - throw new InvalidUserDataException("Invalid version [${s}]") - } - return new Version(m.group(1) as int, m.group(2) as int, - m.group(3) as int, m.group(4) ?: '', m.group(5) != null) - } - - @Override - public String toString() { - String snapshotStr = snapshot ? '-SNAPSHOT' : '' - return "${major}.${minor}.${revision}${suffix}${snapshotStr}" - } - - public boolean before(Version compareTo) { - return id < compareTo.id - } - - public boolean before(String compareTo) { - return before(fromString(compareTo)) - } - - public boolean onOrBefore(Version compareTo) { - return id <= compareTo.id - } - - public boolean onOrBefore(String compareTo) { - return onOrBefore(fromString(compareTo)) - } - - public boolean onOrAfter(Version compareTo) { - return id >= compareTo.id - } - - public boolean onOrAfter(String compareTo) { - return onOrAfter(fromString(compareTo)) - } - - public boolean after(Version compareTo) { - return id > compareTo.id - } - - public boolean after(String compareTo) { - return after(fromString(compareTo)) - } - - public boolean onOrBeforeIncludingSuffix(Version otherVersion) { - if (id != otherVersion.id) { - return id < otherVersion.id - } - - if (suffix == '') { - return otherVersion.suffix == '' - } - - return otherVersion.suffix == '' || suffix < otherVersion.suffix - } - - boolean equals(o) { - if (this.is(o)) return true - if (getClass() != o.class) return false - - Version version = (Version) o - - if (id != version.id) return false - if (major != version.major) return false - if (minor != version.minor) return false - if (revision != version.revision) return false - if (snapshot != version.snapshot) return false - if (suffix != version.suffix) return false - - return true - } - - int hashCode() { - int result - result = major - result = 31 * result + minor - result = 31 * result + revision - result = 31 * result + id - result = 31 * result + (snapshot ? 1 : 0) - result = 31 * result + (suffix != null ? suffix.hashCode() : 0) - return result - } -} diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/LoggedExec.java b/buildSrc/src/main/java/org/elasticsearch/gradle/LoggedExec.java new file mode 100644 index 0000000000000..4eab1232ceb78 --- /dev/null +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/LoggedExec.java @@ -0,0 +1,44 @@ +package org.elasticsearch.gradle; + +import org.gradle.api.GradleException; +import org.gradle.api.tasks.Exec; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +/** + * A wrapper around gradle's Exec task to capture output and log on error. + */ +@SuppressWarnings("unchecked") +public class LoggedExec extends Exec { + + protected ByteArrayOutputStream output = new ByteArrayOutputStream(); + + public LoggedExec() { + if (getLogger().isInfoEnabled() == false) { + setStandardOutput(output); + setErrorOutput(output); + setIgnoreExitValue(true); + doLast((unused) -> { + if (getExecResult().getExitValue() != 0) { + try { + for (String line : output.toString("UTF-8").split("\\R")) { + getLogger().error(line); + } + } catch (UnsupportedEncodingException e) { + throw new GradleException("Failed to read exec output", e); + } + throw new GradleException( + String.format( + "Process '%s %s' finished with non-zero exit value %d", + getExecutable(), + getArgs(), + getExecResult().getExitValue() + ) + ); + } + } + ); + } + } +} diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/Version.java b/buildSrc/src/main/java/org/elasticsearch/gradle/Version.java new file mode 100644 index 0000000000000..53855716840dd --- /dev/null +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/Version.java @@ -0,0 +1,179 @@ +package org.elasticsearch.gradle; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Encapsulates comparison and printing logic for an x.y.z version. + */ +public final class Version implements Comparable { + private final int major; + private final int minor; + private final int revision; + private final int id; + private final boolean snapshot; + /** + * Suffix on the version name. + */ + private final String suffix; + + private static final Pattern pattern = + Pattern.compile("(\\d)+\\.(\\d+)\\.(\\d+)(-alpha\\d+|-beta\\d+|-rc\\d+)?(-SNAPSHOT)?"); + + public Version(int major, int minor, int revision, String suffix, boolean snapshot) { + Objects.requireNonNull(major, "major version can't be null"); + Objects.requireNonNull(minor, "minor version can't be null"); + Objects.requireNonNull(revision, "revision version can't be null"); + this.major = major; + this.minor = minor; + this.revision = revision; + this.snapshot = snapshot; + this.suffix = suffix == null ? "" : suffix; + + int suffixOffset = 0; + if (this.suffix.isEmpty()) { + // no suffix will be considered smaller, uncomment to change that + // suffixOffset = 100; + } else { + if (this.suffix.contains("alpha")) { + suffixOffset += parseSuffixNumber(this.suffix.substring(6)); + } else if (this.suffix.contains("beta")) { + suffixOffset += 25 + parseSuffixNumber(this.suffix.substring(5)); + } else if (this.suffix.contains("rc")) { + suffixOffset += 50 + parseSuffixNumber(this.suffix.substring(3)); + } + else { + throw new IllegalArgumentException("Suffix must contain one of: alpha, beta or rc"); + } + } + + // currently snapshot is not taken into account + this.id = major * 10000000 + minor * 100000 + revision * 1000 + suffixOffset * 10 /*+ (snapshot ? 1 : 0)*/; + } + + private static int parseSuffixNumber(String substring) { + if (substring.isEmpty()) { + throw new IllegalArgumentException("Invalid suffix, must contain a number e.x. alpha2"); + } + return Integer.parseInt(substring); + } + + public static Version fromString(final String s) { + Objects.requireNonNull(s); + Matcher matcher = pattern.matcher(s); + if (matcher.matches() == false) { + throw new IllegalArgumentException( + "Invalid version format: '" + s + "'. Should be major.minor.revision[-(alpha|beta|rc)Number][-SNAPSHOT]" + ); + } + + return new Version( + Integer.parseInt(matcher.group(1)), + parseSuffixNumber(matcher.group(2)), + parseSuffixNumber(matcher.group(3)), + matcher.group(4), + matcher.group(5) != null + ); + } + + @Override + public String toString() { + final String snapshotStr = snapshot ? "-SNAPSHOT" : ""; + return String.valueOf(getMajor()) + "." + String.valueOf(getMinor()) + "." + String.valueOf(getRevision()) + + (suffix == null ? "" : suffix) + snapshotStr; + } + + public boolean before(Version compareTo) { + return id < compareTo.getId(); + } + + public boolean before(String compareTo) { + return before(fromString(compareTo)); + } + + public boolean onOrBefore(Version compareTo) { + return id <= compareTo.getId(); + } + + public boolean onOrBefore(String compareTo) { + return onOrBefore(fromString(compareTo)); + } + + public boolean onOrAfter(Version compareTo) { + return id >= compareTo.getId(); + } + + public boolean onOrAfter(String compareTo) { + return onOrAfter(fromString(compareTo)); + } + + public boolean after(Version compareTo) { + return id > compareTo.getId(); + } + + public boolean after(String compareTo) { + return after(fromString(compareTo)); + } + + public boolean onOrBeforeIncludingSuffix(Version otherVersion) { + if (id != otherVersion.getId()) { + return id < otherVersion.getId(); + } + + if (suffix.equals("")) { + return otherVersion.getSuffix().equals(""); + } + + + return otherVersion.getSuffix().equals("") || suffix.compareTo(otherVersion.getSuffix()) < 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Version version = (Version) o; + return major == version.major && + minor == version.minor && + revision == version.revision && + id == version.id && + snapshot == version.snapshot && + Objects.equals(suffix, version.suffix); + } + + @Override + public int hashCode() { + + return Objects.hash(major, minor, revision, id, snapshot, suffix); + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + public int getRevision() { + return revision; + } + + protected int getId() { + return id; + } + + public boolean isSnapshot() { + return snapshot; + } + + public String getSuffix() { + return suffix; + } + + @Override + public int compareTo(Version other) { + return Integer.compare(getId(), other.getId()); + } +} diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/VersionProperties.java b/buildSrc/src/main/java/org/elasticsearch/gradle/VersionProperties.java similarity index 100% rename from buildSrc/src/main/groovy/org/elasticsearch/gradle/VersionProperties.java rename to buildSrc/src/main/java/org/elasticsearch/gradle/VersionProperties.java diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/precommit/NamingConventionsTask.java b/buildSrc/src/main/java/org/elasticsearch/gradle/precommit/NamingConventionsTask.java similarity index 65% rename from buildSrc/src/main/groovy/org/elasticsearch/gradle/precommit/NamingConventionsTask.java rename to buildSrc/src/main/java/org/elasticsearch/gradle/precommit/NamingConventionsTask.java index 7b63899de31ee..cfbb75456bc6c 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/precommit/NamingConventionsTask.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/precommit/NamingConventionsTask.java @@ -1,7 +1,6 @@ package org.elasticsearch.gradle.precommit; import groovy.lang.Closure; -import org.codehaus.groovy.runtime.ResourceGroovyMethods; import org.elasticsearch.gradle.LoggedExec; import org.elasticsearch.test.NamingConventionsCheck; import org.gradle.api.GradleException; @@ -10,12 +9,12 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.plugins.ExtraPropertiesExtension; import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.AbstractExecTask; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.SourceSetContainer; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.util.Objects; @@ -24,6 +23,7 @@ * tests are named according to our conventions so they'll be picked up by * gradle. Read the Javadoc for NamingConventionsCheck to learn more. */ +@SuppressWarnings("unchecked") public class NamingConventionsTask extends LoggedExec { public NamingConventionsTask() { setDescription("Tests that test classes aren't misnamed or misplaced"); @@ -31,23 +31,23 @@ public NamingConventionsTask() { SourceSetContainer sourceSets = getJavaSourceSets(); final FileCollection classpath = project.files( - // This works because the class only depends on one class from junit that will be available from the - // tests compile classpath. It's the most straight forward way of telling Java where to find the main - // class. - NamingConventionsCheck.class.getProtectionDomain().getCodeSource().getLocation().getPath(), - // the tests to be loaded - checkForTestsInMain ? sourceSets.getByName("main").getRuntimeClasspath() : project.files(), - sourceSets.getByName("test").getCompileClasspath(), - sourceSets.getByName("test").getOutput() + // This works because the class only depends on one class from junit that will be available from the + // tests compile classpath. It's the most straight forward way of telling Java where to find the main + // class. + NamingConventionsCheck.class.getProtectionDomain().getCodeSource().getLocation().getPath(), + // the tests to be loaded + checkForTestsInMain ? sourceSets.getByName("main").getRuntimeClasspath() : project.files(), + sourceSets.getByName("test").getCompileClasspath(), + sourceSets.getByName("test").getOutput() ); dependsOn(project.getTasks().matching(it -> "testCompileClasspath".equals(it.getName()))); getInputs().files(classpath); setExecutable(new File( - Objects.requireNonNull( - project.getExtensions().getByType(ExtraPropertiesExtension.class).get("runtimeJavaHome") - ).toString(), - "bin/java") + Objects.requireNonNull( + project.getExtensions().getByType(ExtraPropertiesExtension.class).get("runtimeJavaHome") + ).toString(), + "bin/java") ); if (checkForTestsInMain == false) { @@ -61,36 +61,34 @@ public NamingConventionsTask() { * We build the arguments in a funny afterEvaluate/doFirst closure so that we can wait for the classpath to be * ready for us. Strangely neither one on their own are good enough. */ - project.afterEvaluate(new Closure(this, this) { - public Task doCall(Project it) { - return doFirst(new Closure(NamingConventionsTask.this, NamingConventionsTask.this) { - public AbstractExecTask doCall(Task it) { - args("-Djna.nosys=true"); - args("-cp", classpath.getAsPath(), "org.elasticsearch.test.NamingConventionsCheck"); - args("--test-class", getTestClass()); - if (skipIntegTestInDisguise) { - args("--skip-integ-tests-in-disguise"); - } else { - args("--integ-test-class", getIntegTestClass()); - } - if (getCheckForTestsInMain()) { - args("--main"); - args("--"); - } else { - args("--"); - } - return args(getExistingClassesDirs().getAsPath()); + project.afterEvaluate(new Closure(this, this) { + public void doCall(Project it) { + doFirst(unused -> { + args("-Djna.nosys=true"); + args("-cp", classpath.getAsPath(), "org.elasticsearch.test.NamingConventionsCheck"); + args("--test-class", getTestClass()); + if (skipIntegTestInDisguise) { + args("--skip-integ-tests-in-disguise"); + } else { + args("--integ-test-class", getIntegTestClass()); } + if (getCheckForTestsInMain()) { + args("--main"); + args("--"); + } else { + args("--"); + } + args(getExistingClassesDirs().getAsPath()); }); } }); - doLast(new Closure(this, this) { - public void doCall(Task it) { - try { - ResourceGroovyMethods.setText(getSuccessMarker(), "", "UTF-8"); - } catch (IOException e) { - throw new GradleException("io exception", e); + doLast((Task it) -> { + try { + try (FileWriter fw = new FileWriter(getSuccessMarker())) { + fw.write(""); } + } catch (IOException e) { + throw new GradleException("io exception", e); } }); } @@ -101,7 +99,7 @@ private SourceSetContainer getJavaSourceSets() { public FileCollection getExistingClassesDirs() { FileCollection classesDirs = getJavaSourceSets().getByName(checkForTestsInMain ? "main" : "test") - .getOutput().getClassesDirs(); + .getOutput().getClassesDirs(); return classesDirs.filter(it -> it.exists()); } diff --git a/buildSrc/src/main/java/org/elasticsearch/test/NamingConventionsCheck.java b/buildSrc/src/main/java/org/elasticsearch/test/NamingConventionsCheck.java index 58e95cfc00232..17d885e21bcc2 100644 --- a/buildSrc/src/main/java/org/elasticsearch/test/NamingConventionsCheck.java +++ b/buildSrc/src/main/java/org/elasticsearch/test/NamingConventionsCheck.java @@ -69,6 +69,10 @@ public static void main(String[] args) throws IOException { fail("unsupported argument '" + arg + "'"); } } + if (rootPathList == null) { + fail("No paths provided"); + return; + } NamingConventionsCheck check = new NamingConventionsCheck(testClass, integTestClass); for (String rootDir : rootPathList.split(Pattern.quote(File.pathSeparator))) { diff --git a/buildSrc/src/test/groovy/org/elasticsearch/gradle/VersionCollectionTests.groovy b/buildSrc/src/test/groovy/org/elasticsearch/gradle/VersionCollectionTests.groovy index 2901acf65220a..ad36c84078398 100644 --- a/buildSrc/src/test/groovy/org/elasticsearch/gradle/VersionCollectionTests.groovy +++ b/buildSrc/src/test/groovy/org/elasticsearch/gradle/VersionCollectionTests.groovy @@ -8,7 +8,7 @@ class VersionCollectionTests extends GradleUnitTestCase { String formatVersion(String version) { return " public static final Version V_${version.replaceAll("\\.", "_")} " } - def allVersions = [formatVersion('5.0.0'), formatVersion('5.0.0_alpha1'), formatVersion('5.0.0_alpha2'), formatVersion('5.0.0_beta1'), + List allVersions = [formatVersion('5.0.0'), formatVersion('5.0.0_alpha1'), formatVersion('5.0.0_alpha2'), formatVersion('5.0.0_beta1'), formatVersion('5.0.0_rc1'),formatVersion('5.0.0_rc2'),formatVersion('5.0.1'), formatVersion('5.0.2'), formatVersion('5.1.1'), formatVersion('5.1.2'), formatVersion('5.2.0'), formatVersion('5.2.1'), formatVersion('6.0.0'), formatVersion('6.0.1'), formatVersion('6.1.0'), formatVersion('6.1.1'), formatVersion('6.2.0'), formatVersion('6.3.0'), @@ -223,7 +223,8 @@ class VersionCollectionTests extends GradleUnitTestCase { Version.fromString("5.1.1"), Version.fromString("5.2.0"), Version.fromString("5.2.1"), Version.fromString("5.3.0"), Version.fromString("5.3.1")] - assertTrue(wireCompatList.containsAll(vc.wireCompatible)) + List compatible = vc.wireCompatible + assertTrue(wireCompatList.containsAll(compatible)) assertTrue(vc.wireCompatible.containsAll(wireCompatList)) assertEquals(vc.snapshotsIndexCompatible.size(), 1) diff --git a/buildSrc/src/test/java/org/elasticsearch/gradle/VersionTests.java b/buildSrc/src/test/java/org/elasticsearch/gradle/VersionTests.java new file mode 100644 index 0000000000000..d3c3b4a43cb41 --- /dev/null +++ b/buildSrc/src/test/java/org/elasticsearch/gradle/VersionTests.java @@ -0,0 +1,181 @@ +package org.elasticsearch.gradle; + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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. + */ + +import org.elasticsearch.gradle.test.GradleUnitTestCase; +import org.junit.Rule; +import org.junit.rules.ExpectedException; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class VersionTests extends GradleUnitTestCase { + + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + + public void testVersionParsing() { + assertVersionEquals("7.0.1", 7, 0, 1, "", false); + assertVersionEquals("7.0.1-alpha2", 7, 0, 1, "-alpha2", false); + assertVersionEquals("5.1.2-rc3", 5, 1, 2, "-rc3", false); + assertVersionEquals("6.1.2-SNAPSHOT", 6, 1, 2, "", true); + assertVersionEquals("6.1.2-beta1-SNAPSHOT", 6, 1, 2, "-beta1", true); + } + + public void testCompareWithStringVersions() { + assertTrue("1.10.20 is not interpreted as before 2.0.0", + Version.fromString("1.10.20").before("2.0.0") + ); + assertTrue("7.0.0-alpha1 is not interpreted as before 7.0.0-alpha2", + Version.fromString("7.0.0-alpha1").before("7.0.0-alpha2") + ); + assertTrue("7.0.0-alpha1 should be equal to 7.0.0-alpha1", + Version.fromString("7.0.0-alpha1").equals(Version.fromString("7.0.0-alpha1")) + ); + assertTrue("7.0.0-SNAPSHOT should be equal to 7.0.0-SNAPSHOT", + Version.fromString("7.0.0-SNAPSHOT").equals(Version.fromString("7.0.0-SNAPSHOT")) + ); + assertEquals(Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("5.2.1-SNAPSHOT")); + } + + public void testCollections() { + assertTrue( + Arrays.asList( + Version.fromString("5.2.0"), Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("6.0.0"), + Version.fromString("6.0.1"), Version.fromString("6.1.0") + ).containsAll(Arrays.asList( + Version.fromString("6.0.1"), Version.fromString("5.2.1-SNAPSHOT") + )) + ); + Set versions = new HashSet<>(); + versions.addAll(Arrays.asList( + Version.fromString("5.2.0"), Version.fromString("5.2.1-SNAPSHOT"), Version.fromString("6.0.0"), + Version.fromString("6.0.1"), Version.fromString("6.1.0") + )); + Set subset = new HashSet<>(); + subset.addAll(Arrays.asList( + Version.fromString("6.0.1"), Version.fromString("5.2.1-SNAPSHOT") + )); + assertTrue(versions.containsAll(subset)); + } + + public void testToString() { + assertEquals("7.0.1", new Version(7, 0, 1, null, false).toString()); + } + + public void testCompareVersions() { + assertEquals(0, new Version(7, 0, 0, null, true).compareTo( + new Version(7, 0, 0, null, true) + )); + assertEquals(0, new Version(7, 0, 0, null, true).compareTo( + new Version(7, 0, 0, "", true) + )); + + // snapshot is not taken into account TODO inconsistent with equals + assertEquals( + 0, + new Version(7, 0, 0, "", false).compareTo( + new Version(7, 0, 0, null, true)) + ); + // without sufix is smaller than with TODO + assertOrder( + new Version(7, 0, 0, null, false), + new Version(7, 0, 0, "-alpha1", false) + ); + // numbered sufix + assertOrder( + new Version(7, 0, 0, "-alpha1", false), + new Version(7, 0, 0, "-alpha2", false) + ); + // ranked sufix + assertOrder( + new Version(7, 0, 0, "-alpha8", false), + new Version(7, 0, 0, "-rc1", false) + ); + // ranked sufix + assertOrder( + new Version(7, 0, 0, "-alpha8", false), + new Version(7, 0, 0, "-beta1", false) + ); + // ranked sufix + assertOrder( + new Version(7, 0, 0, "-beta8", false), + new Version(7, 0, 0, "-rc1", false) + ); + // major takes precedence + assertOrder( + new Version(6, 10, 10, "-alpha8", true), + new Version(7, 0, 0, "-alpha2", false) + ); + // then minor + assertOrder( + new Version(7, 0, 10, "-alpha8", true), + new Version(7, 1, 0, "-alpha2", false) + ); + // then revision + assertOrder( + new Version(7, 1, 0, "-alpha8", true), + new Version(7, 1, 10, "-alpha2", false) + ); + } + + public void testExceptionEmpty() { + expectedEx.expect(IllegalArgumentException.class); + expectedEx.expectMessage("Invalid version format"); + Version.fromString(""); + } + + public void testExceptionSyntax() { + expectedEx.expect(IllegalArgumentException.class); + expectedEx.expectMessage("Invalid version format"); + Version.fromString("foo.bar.baz"); + } + + public void testExceptionSuffixNumber() { + expectedEx.expect(IllegalArgumentException.class); + expectedEx.expectMessage("Invalid suffix"); + new Version(7, 1, 1, "-alpha", true); + } + + public void testExceptionSuffix() { + expectedEx.expect(IllegalArgumentException.class); + expectedEx.expectMessage("Suffix must contain one of:"); + new Version(7, 1, 1, "foo1", true); + } + + private void assertOrder(Version smaller, Version bigger) { + assertEquals(smaller + " should be smaller than " + bigger, -1, smaller.compareTo(bigger)); + } + + private void assertVersionEquals(String stringVersion, int major, int minor, int revision, String sufix, boolean snapshot) { + Version version = Version.fromString(stringVersion); + assertEquals(major, version.getMajor()); + assertEquals(minor, version.getMinor()); + assertEquals(revision, version.getRevision()); + if (snapshot) { + assertTrue("Expected version to be a snapshot but it was not", version.isSnapshot()); + } else { + assertFalse("Expected version not to be a snapshot but it was", version.isSnapshot()); + } + assertEquals(sufix, version.getSuffix()); + } + +}