From 98e9035c5e67a497e954f2c622e345a65d8ea768 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Fri, 19 Jul 2024 22:59:29 -0400 Subject: [PATCH] Added generic version implementation --- src/main/java/rife/bld/BaseProject.java | 2 +- .../rife/bld/dependencies/Dependency.java | 12 +- .../bld/dependencies/DependencyResolver.java | 17 +- .../rife/bld/dependencies/MavenMetadata.java | 22 +- .../java/rife/bld/dependencies/Version.java | 49 ++ .../rife/bld/dependencies/VersionGeneric.java | 374 +++++++++++ .../rife/bld/dependencies/VersionNumber.java | 65 +- .../bld/dependencies/VersionResolution.java | 8 +- .../bld/dependencies/Xml2MavenMetadata.java | 18 +- .../rife/bld/dependencies/Xml2MavenPom.java | 230 +++---- .../operations/AbstractCreateOperation.java | 13 +- .../rife/bld/operations/PublishOperation.java | 12 +- .../rife/bld/publish/MetadataBuilder.java | 7 +- .../java/rife/bld/publish/PublishInfo.java | 7 +- .../bld/dependencies/AbstractVersionTest.java | 47 ++ .../dependencies/TestDependencyResolver.java | 76 +++ .../bld/dependencies/TestVersionGeneric.java | 585 ++++++++++++++++++ .../bld/dependencies/TestVersionNumber.java | 20 +- 18 files changed, 1357 insertions(+), 207 deletions(-) create mode 100644 src/main/java/rife/bld/dependencies/Version.java create mode 100644 src/main/java/rife/bld/dependencies/VersionGeneric.java create mode 100644 src/test/java/rife/bld/dependencies/AbstractVersionTest.java create mode 100644 src/test/java/rife/bld/dependencies/TestVersionGeneric.java diff --git a/src/main/java/rife/bld/BaseProject.java b/src/main/java/rife/bld/BaseProject.java index d9c3016..27e317a 100644 --- a/src/main/java/rife/bld/BaseProject.java +++ b/src/main/java/rife/bld/BaseProject.java @@ -688,7 +688,7 @@ public class BaseProject extends BuildExecutor { * {@link VersionNumber#UNKNOWN} if the description couldn't be parsed * @since 1.5 */ - public VersionNumber version(String description) { + public Version version(String description) { return VersionNumber.parse(description); } diff --git a/src/main/java/rife/bld/dependencies/Dependency.java b/src/main/java/rife/bld/dependencies/Dependency.java index 62b1b78..725ce5d 100644 --- a/src/main/java/rife/bld/dependencies/Dependency.java +++ b/src/main/java/rife/bld/dependencies/Dependency.java @@ -20,7 +20,7 @@ import java.util.regex.Pattern; * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @since 1.5 */ -public record Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { +public record Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { public static final String CLASSIFIER_SOURCES = "sources"; public static final String CLASSIFIER_JAVADOC = "javadoc"; @@ -28,23 +28,23 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio this(groupId, artifactId, null, null, null); } - public Dependency(String groupId, String artifactId, VersionNumber version) { + public Dependency(String groupId, String artifactId, Version version) { this(groupId, artifactId, version, null, null); } - public Dependency(String groupId, String artifactId, VersionNumber version, String classifier) { + public Dependency(String groupId, String artifactId, Version version, String classifier) { this(groupId, artifactId, version, classifier, null); } - public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type) { + public Dependency(String groupId, String artifactId, Version version, String classifier, String type) { this(groupId, artifactId, version, classifier, type, null); } - public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions) { + public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions) { this(groupId, artifactId, version, classifier, type, exclusions, null); } - public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { + public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { this.groupId = groupId; this.artifactId = artifactId; this.version = (version == null ? VersionNumber.UNKNOWN : version); diff --git a/src/main/java/rife/bld/dependencies/DependencyResolver.java b/src/main/java/rife/bld/dependencies/DependencyResolver.java index 8cb065d..24b7bef 100644 --- a/src/main/java/rife/bld/dependencies/DependencyResolver.java +++ b/src/main/java/rife/bld/dependencies/DependencyResolver.java @@ -78,7 +78,7 @@ public class DependencyResolver { * @return the resolved version * @since 1.5 */ - public VersionNumber resolveVersion() { + public Version resolveVersion() { var version = resolution_.overrideVersion(dependency_); if (version.equals(VersionNumber.UNKNOWN)) { return latestVersion(); @@ -191,7 +191,7 @@ public class DependencyResolver { * couldn't be found in the provided repositories * @since 1.5 */ - public List listVersions() { + public List listVersions() { return getMavenMetadata().getVersions(); } @@ -202,7 +202,7 @@ public class DependencyResolver { * if the dependency couldn't be found in the provided repositories * @since 1.5 */ - public VersionNumber latestVersion() { + public Version latestVersion() { return getMavenMetadata().getLatest(); } @@ -213,7 +213,7 @@ public class DependencyResolver { * if the dependency couldn't be found in the provided repositories * @since 1.5 */ - public VersionNumber releaseVersion() { + public Version releaseVersion() { return getMavenMetadata().getRelease(); } @@ -318,7 +318,7 @@ public class DependencyResolver { private List getTransferArtifacts() { final var version = resolveVersion(); - final VersionNumber pom_version; + final Version pom_version; if (version.isSnapshot()) { var metadata = getSnapshotMavenMetadata(); pom_version = metadata.getSnapshot(); @@ -400,7 +400,7 @@ public class DependencyResolver { private List getPomLocations() { final var version = resolveVersion(); - final VersionNumber pom_version; + final Version pom_version; if (version.isSnapshot()) { var metadata = getSnapshotMavenMetadata(); pom_version = metadata.getSnapshot(); @@ -449,6 +449,11 @@ public class DependencyResolver { } var xml = new Xml2MavenPom(parent, resolution_, retriever_, repositories_); + // first pass only extracts the properties from the pom + if (!xml.processXml(pom)) { + throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors()); + } + // second pass parses all the rest so that the properties are available anywhere if (!xml.processXml(pom)) { throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors()); } diff --git a/src/main/java/rife/bld/dependencies/MavenMetadata.java b/src/main/java/rife/bld/dependencies/MavenMetadata.java index b901941..0dec24e 100644 --- a/src/main/java/rife/bld/dependencies/MavenMetadata.java +++ b/src/main/java/rife/bld/dependencies/MavenMetadata.java @@ -14,28 +14,28 @@ import java.util.List; */ public interface MavenMetadata { /** - * Returns latest version number in the metadata. + * Returns latest version in the metadata. * - * @return the latest version number + * @return the latest version * @since 1.5.8 */ - VersionNumber getLatest(); + Version getLatest(); /** - * Returns release version number in the metadata. + * Returns release version in the metadata. * - * @return the release version number + * @return the release version * @since 1.5.8 */ - VersionNumber getRelease(); + Version getRelease(); /** - * Returns snapshot version number in the metadata. + * Returns snapshot version in the metadata. * - * @return the snapshot version number + * @return the snapshot version * @since 1.5.8 */ - VersionNumber getSnapshot(); + Version getSnapshot(); /** * Returns snapshot timestamp in the metadata. @@ -56,8 +56,8 @@ public interface MavenMetadata { /** * Returns all the release or snapshot versions in the metadata. * - * @return the version number list + * @return the version list * @since 1.5.8 */ - List getVersions(); + List getVersions(); } diff --git a/src/main/java/rife/bld/dependencies/Version.java b/src/main/java/rife/bld/dependencies/Version.java new file mode 100644 index 0000000..c77e7e0 --- /dev/null +++ b/src/main/java/rife/bld/dependencies/Version.java @@ -0,0 +1,49 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Licensed under the Apache License, Version 2.0 (the "License") + */ +package rife.bld.dependencies; + +/** + * Represents the basic functionality of a dependency version. + * + * @since 2.0 + */ +public interface Version extends Comparable { + /** + * Retrieves the qualifier of the version. + * + * @return this version's qualifier + * @since 2.0 + */ + String qualifier(); + + /** + * Retrieves the version number with a different qualifier. + * + * @return this version number with a different qualifier + * @since 2.0 + */ + Version withQualifier(String qualifier); + + /** + * Indicates whether this is a snapshot version. + * + * @return {@code true} if this is a snapshot version; or + * {@code false} otherwise + * @since 2.0 + */ + boolean isSnapshot(); + + @Override + int compareTo(Version other); + + @Override + String toString(); + + @Override + boolean equals(Object other); + + @Override + int hashCode(); +} diff --git a/src/main/java/rife/bld/dependencies/VersionGeneric.java b/src/main/java/rife/bld/dependencies/VersionGeneric.java new file mode 100644 index 0000000..aadfcc3 --- /dev/null +++ b/src/main/java/rife/bld/dependencies/VersionGeneric.java @@ -0,0 +1,374 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Licensed under the Apache License, Version 2.0 (the "License") + */ +package rife.bld.dependencies; + +import java.math.BigInteger; +import java.util.*; + +import static java.util.Objects.requireNonNull; + +/** + * + * @since 2.0 + */ +// https://github.com/apache/maven-resolver/blob/98126539f3c66fc4ab50b178c2eb4b8fd169fd72/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java +public class VersionGeneric implements Version { + private final String version_; + private final List items_; + private final int hash_; + + @Override + public String qualifier() { + return ""; + } + + @Override + public Version withQualifier(String qualifier) { + return new VersionGeneric(version_); + } + + @Override + public boolean isSnapshot() { + return false; + } + + /** + * Creates a generic version from the specified string. + * + * @param version The version string, must not be {@code null}. + * @since 2.0 + */ + VersionGeneric(String version) { + version_ = requireNonNull(version, "version cannot be null"); + items_ = parse(version); + hash_ = items_.hashCode(); + } + + /** + * Returns this instance tokenized representation as unmodifiable list. + * + * @since 2.0 + */ + public List asItems() { + return items_; + } + + private static List parse(String version) { + var items = new ArrayList(); + + for (var tokenizer = new Tokenizer(version); tokenizer.next(); ) { + var item = tokenizer.toItem(); + items.add(item); + } + + trimPadding(items); + + return Collections.unmodifiableList(items); + } + + /** + * Visible for testing. + */ + public static void trimPadding(List items) { + Boolean number = null; + var end = items.size() - 1; + for (var i = end; i > 0; i--) { + var item = items.get(i); + if (!Boolean.valueOf(item.isNumber()).equals(number)) { + end = i; + number = item.isNumber(); + } + if (end == i + && (i == items.size() - 1 || items.get(i - 1).isNumber() == item.isNumber()) + && item.compareTo(null) == 0) { + items.remove(i); + end--; + } + } + } + + @Override + public int compareTo(Version other) { + VersionGeneric generic; + if (other instanceof VersionGeneric) { + generic = (VersionGeneric)other; + } + else { + generic = new VersionGeneric(other.toString()); + } + + final var these = items_; + final var those = generic.items_; + + var number = true; + + for (var index = 0; ; index++) { + if (index >= these.size() && index >= those.size()) { + return 0; + } else if (index >= these.size()) { + return -comparePadding(those, index, null); + } else if (index >= those.size()) { + return comparePadding(these, index, null); + } + + var thisItem = these.get(index); + var thatItem = those.get(index); + + if (thisItem.isNumber() != thatItem.isNumber()) { + if (index == 0) { + return thisItem.compareTo(thatItem); + } + if (number == thisItem.isNumber()) { + return comparePadding(these, index, number); + } else { + return -comparePadding(those, index, number); + } + } else { + var rel = thisItem.compareTo(thatItem); + if (rel != 0) { + return rel; + } + number = thisItem.isNumber(); + } + } + } + + private static int comparePadding(List items, int index, Boolean number) { + var rel = 0; + for (var i = index; i < items.size(); i++) { + var item = items.get(i); + if (number != null && number != item.isNumber()) { + // do not stop here, but continue, skipping non-number members + continue; + } + rel = item.compareTo(null); + if (rel != 0) { + break; + } + } + return rel; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof VersionGeneric) && compareTo((VersionGeneric) obj) == 0; + } + + @Override + public int hashCode() { + return hash_; + } + + @Override + public String toString() { + return version_; + } + + static final class Tokenizer { + private static final Integer QUALIFIER_ALPHA = -5; + private static final Integer QUALIFIER_BETA = -4; + private static final Integer QUALIFIER_MILESTONE = -3; + private static final Map QUALIFIERS; + + static { + QUALIFIERS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + QUALIFIERS.put("alpha", QUALIFIER_ALPHA); + QUALIFIERS.put("beta", QUALIFIER_BETA); + QUALIFIERS.put("milestone", QUALIFIER_MILESTONE); + QUALIFIERS.put("cr", -2); + QUALIFIERS.put("rc", -2); + QUALIFIERS.put("snapshot", -1); + QUALIFIERS.put("ga", 0); + QUALIFIERS.put("final", 0); + QUALIFIERS.put("release", 0); + QUALIFIERS.put("", 0); + QUALIFIERS.put("sp", 1); + } + + private final String version_; + private final int versionLength_; + private int index_; + private String token_; + private boolean number_; + private boolean terminatedByNumber_; + + Tokenizer(String version) { + version_ = (!version.isEmpty()) ? version : "0"; + versionLength_ = this.version_.length(); + } + + public boolean next() { + if (index_ >= versionLength_) { + return false; + } + + var state = -2; + + var start = index_; + var end = versionLength_; + terminatedByNumber_ = false; + + for (; index_ < versionLength_; index_++) { + var c = version_.charAt(index_); + + if (c == '.' || c == '-' || c == '_') { + end = index_; + index_++; + break; + } else { + var digit = Character.digit(c, 10); + if (digit >= 0) { + if (state == -1) { + end = index_; + terminatedByNumber_ = true; + break; + } + if (state == 0) { + // normalize numbers and strip leading zeros (prereq for Integer/BigInteger handling) + start++; + } + state = (state > 0 || digit > 0) ? 1 : 0; + } else { + if (state >= 0) { + end = index_; + break; + } + state = -1; + } + } + } + + if (end - start > 0) { + token_ = version_.substring(start, end); + number_ = state >= 0; + } else { + token_ = "0"; + number_ = true; + } + + return true; + } + + @Override + public String toString() { + return String.valueOf(token_); + } + + public Item toItem() { + if (number_) { + try { + if (token_.length() < 10) { + return new Item(Item.KIND_INT, Integer.parseInt(token_)); + } else { + return new Item(Item.KIND_BIGINT, new BigInteger(token_)); + } + } catch (NumberFormatException e) { + throw new IllegalStateException(e); + } + } else { + if (index_ >= version_.length()) { + if ("min".equalsIgnoreCase(token_)) { + return Item.MIN; + } else if ("max".equalsIgnoreCase(token_)) { + return Item.MAX; + } + } + if (terminatedByNumber_ && token_.length() == 1) { + switch (token_.charAt(0)) { + case 'a': + case 'A': + return new Item(Item.KIND_QUALIFIER, QUALIFIER_ALPHA); + case 'b': + case 'B': + return new Item(Item.KIND_QUALIFIER, QUALIFIER_BETA); + case 'm': + case 'M': + return new Item(Item.KIND_QUALIFIER, QUALIFIER_MILESTONE); + default: + } + } + var qualifier = QUALIFIERS.get(token_); + if (qualifier != null) { + return new Item(Item.KIND_QUALIFIER, qualifier); + } else { + return new Item(Item.KIND_STRING, token_.toLowerCase(Locale.ENGLISH)); + } + } + } + } + + static final class Item { + static final int KIND_MAX = 8; + static final int KIND_BIGINT = 5; + static final int KIND_INT = 4; + static final int KIND_STRING = 3; + static final int KIND_QUALIFIER = 2; + static final int KIND_MIN = 0; + static final Item MAX = new Item(KIND_MAX, "max"); + static final Item MIN = new Item(KIND_MIN, "min"); + + private final int kind_; + private final Object value_; + + Item(int kind, Object value) { + kind_ = kind; + value_ = value; + } + + public boolean isNumber() { + return (kind_ & KIND_QUALIFIER) == 0; // i.e. kind != string/qualifier + } + + public int compareTo(Item that) { + int rel; + if (that == null) { + // null in this context denotes the pad item (0 or "ga") + rel = switch (kind_) { + case KIND_MIN -> -1; + case KIND_MAX, KIND_BIGINT, KIND_STRING -> 1; + case KIND_INT, KIND_QUALIFIER -> (Integer) value_; + default -> throw new IllegalStateException("unknown version item kind " + kind_); + }; + } else { + rel = kind_ - that.kind_; + if (rel == 0) { + switch (kind_) { + case KIND_MAX: + case KIND_MIN: + break; + case KIND_BIGINT: + rel = ((BigInteger) value_).compareTo((BigInteger) that.value_); + break; + case KIND_INT: + case KIND_QUALIFIER: + rel = ((Integer) value_).compareTo((Integer) that.value_); + break; + case KIND_STRING: + rel = ((String) value_).compareToIgnoreCase((String) that.value_); + break; + default: + throw new IllegalStateException("unknown version item kind " + kind_); + } + } + } + return rel; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof Item) && compareTo((Item) obj) == 0; + } + + @Override + public int hashCode() { + return value_.hashCode() + kind_ * 31; + } + + @Override + public String toString() { + return String.valueOf(value_); + } + } +} diff --git a/src/main/java/rife/bld/dependencies/VersionNumber.java b/src/main/java/rife/bld/dependencies/VersionNumber.java index 1879c9d..f9b3fb5 100644 --- a/src/main/java/rife/bld/dependencies/VersionNumber.java +++ b/src/main/java/rife/bld/dependencies/VersionNumber.java @@ -22,7 +22,7 @@ import java.util.regex.Pattern; * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @since 1.5 */ -public record VersionNumber(Integer major, Integer minor, Integer revision, String qualifier, String separator) implements Comparable { +public record VersionNumber(Integer major, Integer minor, Integer revision, String qualifier, String separator) implements Version { public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT"; /** @@ -44,14 +44,14 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri * {@link VersionNumber#UNKNOWN} when the string couldn't be parsed * @since 1.5 */ - public static VersionNumber parse(String version) { + public static Version parse(String version) { if (version == null || version.isEmpty()) { return UNKNOWN; } var matcher = VERSION_PATTERN.matcher(version); if (!matcher.matches()) { - return UNKNOWN; + return new VersionGeneric(version); } var major = matcher.group("major"); @@ -142,13 +142,8 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri return new VersionNumber(major, minor, revision, null); } - /** - * Retrieves the version number with a different qualifier. - * - * @return this version number with a different qualifier - * @since 1.5.8 - */ - public VersionNumber withQualifier(String qualifier) { + @Override + public Version withQualifier(String qualifier) { return new VersionNumber(major, minor, revision, qualifier); } @@ -182,37 +177,35 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri return revision == null ? 0 : revision; } - /** - * Indicates whether this is a snapshot version. - * - * @return {@code true} if this is a snapshot version; or - * {@code false} otherwise - * @since 1.5.8 - */ public boolean isSnapshot() { return qualifier().toUpperCase().contains(SNAPSHOT_QUALIFIER); } - public int compareTo(VersionNumber other) { - if (majorInt() != other.majorInt()) { - return majorInt() - other.majorInt(); - } - if (minorInt() != other.minorInt()) { - return minorInt() - other.minorInt(); - } - if (revisionInt() != other.revisionInt()) { - return revisionInt() - other.revisionInt(); + @Override + public int compareTo(Version other) { + if (other instanceof VersionNumber otherNumber) { + if (majorInt() != otherNumber.majorInt()) { + return majorInt() - otherNumber.majorInt(); + } + if (minorInt() != otherNumber.minorInt()) { + return minorInt() - otherNumber.minorInt(); + } + if (revisionInt() != otherNumber.revisionInt()) { + return revisionInt() - otherNumber.revisionInt(); + } + + if (qualifier.equals(otherNumber.qualifier)) { + return 0; + } else if (qualifier.isEmpty()) { + return 1; + } else if (otherNumber.qualifier.isEmpty()) { + return -1; + } + + return qualifier.toLowerCase().compareTo(otherNumber.qualifier.toLowerCase()); } - if (qualifier.equals(other.qualifier)) { - return 0; - } else if (qualifier.isEmpty()) { - return 1; - } else if (other.qualifier.isEmpty()) { - return -1; - } - - return qualifier.toLowerCase().compareTo(other.qualifier.toLowerCase()); + return toString().compareTo(other.toString()); } public String toString() { @@ -235,7 +228,7 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri @Override public boolean equals(Object other) { - return other instanceof VersionNumber && compareTo((VersionNumber) other) == 0; + return other instanceof Version && compareTo((Version) other) == 0; } @Override diff --git a/src/main/java/rife/bld/dependencies/VersionResolution.java b/src/main/java/rife/bld/dependencies/VersionResolution.java index c010f17..462f375 100644 --- a/src/main/java/rife/bld/dependencies/VersionResolution.java +++ b/src/main/java/rife/bld/dependencies/VersionResolution.java @@ -36,7 +36,7 @@ public class VersionResolution { */ public static final String PROPERTY_OVERRIDE_PREFIX = "bld.override"; - private final Map versionOverrides_ = new HashMap<>(); + private final Map versionOverrides_ = new HashMap<>(); /** * Returns a dummy {@code VersionResolution} instance that doesn't override anything. @@ -49,7 +49,7 @@ public class VersionResolution { } /** - * Creates a new instance of the {@code VersionReslution} class from hierarchical properties that + * Creates a new instance of the {@code VersionResolution} class from hierarchical properties that * are passed in. *

* The actual version overrides are determined at instantiation time and any future changes to the @@ -83,7 +83,7 @@ public class VersionResolution { * @return the overridden version if it is available; or the original version otherwise * @since 2.0 */ - public VersionNumber overrideVersion(Dependency original) { + public Version overrideVersion(Dependency original) { var overridden = versionOverrides_.get(original.toArtifactString()); if (overridden == null) { return original.version(); @@ -119,7 +119,7 @@ public class VersionResolution { * @return the map of version overrides * @since 2.0 */ - public Map versionOverrides() { + public Map versionOverrides() { return versionOverrides_; } } diff --git a/src/main/java/rife/bld/dependencies/Xml2MavenMetadata.java b/src/main/java/rife/bld/dependencies/Xml2MavenMetadata.java index e94a36a..43f3e1c 100644 --- a/src/main/java/rife/bld/dependencies/Xml2MavenMetadata.java +++ b/src/main/java/rife/bld/dependencies/Xml2MavenMetadata.java @@ -18,10 +18,10 @@ import java.util.regex.Pattern; * @since 1.5.8 */ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata { - private VersionNumber latest_ = VersionNumber.UNKNOWN; - private VersionNumber release_ = VersionNumber.UNKNOWN; - private final List versions_; - private VersionNumber snapshot_ = VersionNumber.UNKNOWN; + private Version latest_ = VersionNumber.UNKNOWN; + private Version release_ = VersionNumber.UNKNOWN; + private final List versions_; + private Version snapshot_ = VersionNumber.UNKNOWN; private StringBuilder characterData_ = null; @@ -33,15 +33,15 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata { versions_ = new ArrayList<>(); } - public VersionNumber getLatest() { + public Version getLatest() { return latest_; } - public VersionNumber getRelease() { + public Version getRelease() { return release_; } - public VersionNumber getSnapshot() { + public Version getSnapshot() { return snapshot_; } @@ -53,7 +53,7 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata { return snapshotBuildNumber_; } - public List getVersions() { + public List getVersions() { return versions_; } @@ -87,7 +87,7 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata { if (snapshotTimestamp_ != null && snapshotBuildNumber_ != null) { qualifier = snapshotTimestamp_ + "-" + snapshotBuildNumber_; } - snapshot_ = new VersionNumber(version.major(), version.minor(), version.revision(), qualifier); + snapshot_ = version.withQualifier(qualifier); } } diff --git a/src/main/java/rife/bld/dependencies/Xml2MavenPom.java b/src/main/java/rife/bld/dependencies/Xml2MavenPom.java index 8d1f5fe..2268914 100644 --- a/src/main/java/rife/bld/dependencies/Xml2MavenPom.java +++ b/src/main/java/rife/bld/dependencies/Xml2MavenPom.java @@ -29,6 +29,7 @@ class Xml2MavenPom extends Xml2Data { private final Stack elementStack_ = new Stack<>(); private ExclusionSet exclusions_ = null; + private boolean initialParse_ = true; private boolean collectProperties_ = false; private boolean collectDependencyManagement_ = false; private boolean collectDependencies_ = false; @@ -142,32 +143,36 @@ class Xml2MavenPom extends Xml2Data { public void startElement(String uri, String localName, String qName, Attributes attributes) { characterData_ = new StringBuilder(); - switch (qName) { - case "parent" -> resetState(); - case "properties" -> { + if (initialParse_) { + if (qName.equals("properties")) { if (isChildOfProject()) { collectProperties_ = true; } } - case "dependencyManagement" -> { - if (isChildOfProject()) { - collectDependencyManagement_ = true; + } + else { + switch (qName) { + case "parent" -> resetState(); + case "dependencyManagement" -> { + if (isChildOfProject()) { + collectDependencyManagement_ = true; + } } - } - case "dependencies" -> { - if (isChildOfProject()) { - resetState(); - collectDependencies_ = true; + case "dependencies" -> { + if (isChildOfProject()) { + resetState(); + collectDependencies_ = true; + } } - } - case "exclusions" -> { - if (collectDependencyManagement_ || collectDependencies_) { - collectExclusions_ = true; - exclusions_ = new ExclusionSet(); + case "exclusions" -> { + if (collectDependencyManagement_ || collectDependencies_) { + collectExclusions_ = true; + exclusions_ = new ExclusionSet(); + } + } + case "dependency" -> { + if (collectDependencies_) resetState(); } - } - case "dependency" -> { - if (collectDependencies_) resetState(); } } @@ -177,110 +182,117 @@ class Xml2MavenPom extends Xml2Data { public void endElement(String uri, String localName, String qName) { elementStack_.pop(); - switch (qName) { - case "parent" -> { - if (isChildOfProject()) { - var parent_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), VersionNumber.parse(resolveMavenProperties(lastVersion_))); - var parent = new DependencyResolver(resolution_, retriever_, repositories_, parent_dependency).getMavenPom(parent_); + if (initialParse_) { + switch (qName) { + case "properties" -> collectProperties_ = false; + case "project" -> initialParse_ = false; + default -> { + if (collectProperties_) { + mavenProperties_.put(qName, getCharacterData()); + } + } + } + } + else { + switch (qName) { + case "parent" -> { + if (isChildOfProject()) { + var parent_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), VersionNumber.parse(resolveMavenProperties(lastVersion_))); + var parent = new DependencyResolver(resolution_, retriever_, repositories_, parent_dependency).getMavenPom(parent_); - parent.mavenProperties_.keySet().removeAll(mavenProperties_.keySet()); - mavenProperties_.putAll(parent.mavenProperties_); + parent.mavenProperties_.keySet().removeAll(mavenProperties_.keySet()); + mavenProperties_.putAll(parent.mavenProperties_); - parent.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); - dependencyManagement_.putAll(parent.dependencyManagement_); + parent.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); + dependencyManagement_.putAll(parent.dependencyManagement_); - parent.dependencies_.removeAll(dependencies_); - dependencies_.addAll(parent.dependencies_); + parent.dependencies_.removeAll(dependencies_); + dependencies_.addAll(parent.dependencies_); + resetState(); + } + } + case "dependencyManagement" -> collectDependencyManagement_ = false; + case "dependencies" -> collectDependencies_ = false; + case "exclusions" -> collectExclusions_ = false; + case "exclusion" -> { + if (collectExclusions_) { + exclusions_.add(new DependencyExclusion(lastExclusionGroupId_, lastExclusionArtifactId_)); + } + } + case "dependency" -> { + var dependency = new PomDependency(lastGroupId_, lastArtifactId_, lastVersion_, lastClassifier_, lastType_, lastScope_, lastOptional_, exclusions_, parent_); + if (collectDependencyManagement_) { + if (dependency.isPomImport()) { + var import_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), VersionNumber.parse(resolveMavenProperties(lastVersion_))); + var imported_pom = new DependencyResolver(resolution_, retriever_, repositories_, import_dependency).getMavenPom(parent_); + imported_pom.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); + var resolved_dependencies = new LinkedHashSet(); + for (var managed_dependency : imported_pom.dependencyManagement_.keySet()) { + resolved_dependencies.add(imported_pom.resolveDependency(managed_dependency)); + } + + resolved_dependencies.removeAll(dependencyManagement_.keySet()); + for (var resolved_dependency : resolved_dependencies) { + dependencyManagement_.put(resolved_dependency, resolved_dependency); + } + } else { + dependencyManagement_.put(dependency, dependency); + } + } else if (collectDependencies_) { + dependencies_.add(dependency); + } resetState(); } - } - case "properties" -> collectProperties_ = false; - case "dependencyManagement" -> collectDependencyManagement_ = false; - case "dependencies" -> collectDependencies_ = false; - case "exclusions" -> collectExclusions_ = false; - case "exclusion" -> { - if (collectExclusions_) { - exclusions_.add(new DependencyExclusion(lastExclusionGroupId_, lastExclusionArtifactId_)); - } - } - case "dependency" -> { - var dependency = new PomDependency(lastGroupId_, lastArtifactId_, lastVersion_, lastClassifier_, lastType_, lastScope_, lastOptional_, exclusions_, parent_); - if (collectDependencyManagement_) { - if (dependency.isPomImport()) { - var import_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), VersionNumber.parse(resolveMavenProperties(lastVersion_))); - var imported_pom = new DependencyResolver(resolution_, retriever_, repositories_, import_dependency).getMavenPom(parent_); - imported_pom.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); - var resolved_dependencies = new LinkedHashSet(); - for (var managed_dependency : imported_pom.dependencyManagement_.keySet()) { - resolved_dependencies.add(imported_pom.resolveDependency(managed_dependency)); - } - - resolved_dependencies.removeAll(dependencyManagement_.keySet()); - for (var resolved_dependency : resolved_dependencies) { - dependencyManagement_.put(resolved_dependency, resolved_dependency); - } - } else { - dependencyManagement_.put(dependency, dependency); + case "groupId" -> { + if (isChildOfProject()) { + addProjectProperty(qName); + } else if (isChildOfParent() || isChildOfDependency()) { + lastGroupId_ = getCharacterData(); + } else if (collectExclusions_ && isChildOfExclusion()) { + lastExclusionGroupId_ = getCharacterData(); } - } else if (collectDependencies_) { - dependencies_.add(dependency); } - resetState(); - } - case "groupId" -> { - if (isChildOfProject()) { - addProjectProperty(qName); - } else if (isChildOfParent() || isChildOfDependency()) { - lastGroupId_ = getCharacterData(); - } else if (collectExclusions_ && isChildOfExclusion()) { - lastExclusionGroupId_ = getCharacterData(); + case "artifactId" -> { + if (isChildOfProject()) { + addProjectProperty(qName); + } else if (isChildOfParent() || isChildOfDependency()) { + lastArtifactId_ = getCharacterData(); + } else if (collectExclusions_ && isChildOfExclusion()) { + lastExclusionArtifactId_ = getCharacterData(); + } } - } - case "artifactId" -> { - if (isChildOfProject()) { - addProjectProperty(qName); - } else if (isChildOfParent() || isChildOfDependency()) { - lastArtifactId_ = getCharacterData(); - } else if (collectExclusions_ && isChildOfExclusion()) { - lastExclusionArtifactId_ = getCharacterData(); + case "version" -> { + if (isChildOfProject()) { + addProjectProperty(qName); + } else if (isChildOfParent() || isChildOfDependency()) { + lastVersion_ = getCharacterData(); + } } - } - case "version" -> { - if (isChildOfProject()) { - addProjectProperty(qName); - } else if (isChildOfParent() || isChildOfDependency()) { - lastVersion_ = getCharacterData(); + case "type" -> { + if (isChildOfDependency()) { + lastType_ = getCharacterData(); + } } - } - case "type" -> { - if (isChildOfDependency()) { - lastType_ = getCharacterData(); + case "classifier" -> { + if (isChildOfDependency()) { + lastClassifier_ = getCharacterData(); + } } - } - case "classifier" -> { - if (isChildOfDependency()) { - lastClassifier_ = getCharacterData(); + case "scope" -> { + if (isChildOfDependency()) { + lastScope_ = getCharacterData(); + } } - } - case "scope" -> { - if (isChildOfDependency()) { - lastScope_ = getCharacterData(); + case "optional" -> { + if (isChildOfDependency()) { + lastOptional_ = getCharacterData(); + } } - } - case "optional" -> { - if (isChildOfDependency()) { - lastOptional_ = getCharacterData(); - } - } - case "packaging", "name", "description", "url", "inceptionYear" -> { - if (isChildOfProject()) { - addProjectProperty(qName); - } - } - default -> { - if (collectProperties_) { - mavenProperties_.put(qName, getCharacterData()); + case "packaging", "name", "description", "url", "inceptionYear" -> { + if (isChildOfProject()) { + addProjectProperty(qName); + } } } } diff --git a/src/main/java/rife/bld/operations/AbstractCreateOperation.java b/src/main/java/rife/bld/operations/AbstractCreateOperation.java index b20c5d5..8de2cae 100644 --- a/src/main/java/rife/bld/operations/AbstractCreateOperation.java +++ b/src/main/java/rife/bld/operations/AbstractCreateOperation.java @@ -6,6 +6,7 @@ package rife.bld.operations; import rife.bld.BldVersion; import rife.bld.Project; +import rife.bld.dependencies.VersionNumber; import rife.bld.operations.exceptions.OperationOptionException; import rife.bld.wrapper.Wrapper; import rife.template.TemplateFactory; @@ -228,9 +229,15 @@ public abstract class AbstractCreateOperation { * * @param repository the repository to publish to * @param moment the timestamp at which the operation started executing - * @return the adapted version number with the snapshot timestamp and build number + * @return the adapted version with the snapshot timestamp and build number * @since 1.5.10 */ - protected VersionNumber executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) { + protected Version executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) { var metadata = new MetadataBuilder(); - VersionNumber actual_version; + Version actual_version; if (repository.isLocal()) { actual_version = info().version(); metadata.snapshotLocal(); @@ -172,7 +172,7 @@ public class PublishOperation extends AbstractOperation { * @param actualVersion the version that was potentially adapted if this is a snapshot * @since 1.5.10 */ - protected void executePublishArtifacts(Repository repository, VersionNumber actualVersion) { + protected void executePublishArtifacts(Repository repository, Version actualVersion) { // upload artifacts for (var artifact : artifacts()) { var artifact_name = new StringBuilder(info().artifactId()).append('-').append(actualVersion); @@ -196,7 +196,7 @@ public class PublishOperation extends AbstractOperation { * @param actualVersion the version that was potentially adapted if this is a snapshot * @since 1.5.10 */ - protected void executePublishPom(Repository repository, VersionNumber actualVersion) { + protected void executePublishPom(Repository repository, Version actualVersion) { // generate and upload pom executePublishStringArtifact( repository, @@ -212,7 +212,7 @@ public class PublishOperation extends AbstractOperation { * @since 1.5.8 */ protected void executePublishMetadata(Repository repository, ZonedDateTime moment) { - var current_versions = new ArrayList(); + var current_versions = new ArrayList(); var resolution = new VersionResolution(properties()); var resolver = new DependencyResolver(resolution, artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version())); try { diff --git a/src/main/java/rife/bld/publish/MetadataBuilder.java b/src/main/java/rife/bld/publish/MetadataBuilder.java index 31c77df..bc6138b 100644 --- a/src/main/java/rife/bld/publish/MetadataBuilder.java +++ b/src/main/java/rife/bld/publish/MetadataBuilder.java @@ -4,6 +4,7 @@ */ package rife.bld.publish; +import rife.bld.dependencies.Version; import rife.bld.dependencies.VersionNumber; import rife.template.TemplateFactory; import rife.tools.StringUtils; @@ -24,7 +25,7 @@ public class MetadataBuilder { private PublishInfo info_ = null; private ZonedDateTime timestamp_ = null; - private final Set otherVersions_ = new HashSet<>(); + private final Set otherVersions_ = new HashSet<>(); private ZonedDateTime snapshotTimestamp_ = null; private Integer snapshotBuildNumber_ = null; private boolean snapshotLocal_ = false; @@ -81,7 +82,7 @@ public class MetadataBuilder { * @return this {@code MetadataBuilder} instance * @since 1.5.8 */ - public MetadataBuilder otherVersions(Collection otherVersions) { + public MetadataBuilder otherVersions(Collection otherVersions) { otherVersions_.addAll(otherVersions); return this; } @@ -94,7 +95,7 @@ public class MetadataBuilder { * @return the other versions * @since 1.5.8 */ - public Set otherVersions() { + public Set otherVersions() { return otherVersions_; } diff --git a/src/main/java/rife/bld/publish/PublishInfo.java b/src/main/java/rife/bld/publish/PublishInfo.java index 07a8337..6cc6bb9 100644 --- a/src/main/java/rife/bld/publish/PublishInfo.java +++ b/src/main/java/rife/bld/publish/PublishInfo.java @@ -4,6 +4,7 @@ */ package rife.bld.publish; +import rife.bld.dependencies.Version; import rife.bld.dependencies.VersionNumber; import java.util.ArrayList; @@ -18,7 +19,7 @@ import java.util.List; public class PublishInfo { private String groupId_ = null; private String artifactId_ = null; - private VersionNumber version_ = null; + private Version version_ = null; private String name_ = null; private String description_ = null; private String url_ = null; @@ -81,7 +82,7 @@ public class PublishInfo { * @return this {@code PublishInfo} instance * @since 1.5.7 */ - public PublishInfo version(VersionNumber version) { + public PublishInfo version(Version version) { version_ = version; return this; } @@ -92,7 +93,7 @@ public class PublishInfo { * @return the project's version. * @since 1.5.7 */ - public VersionNumber version() { + public Version version() { return version_; } diff --git a/src/test/java/rife/bld/dependencies/AbstractVersionTest.java b/src/test/java/rife/bld/dependencies/AbstractVersionTest.java new file mode 100644 index 0000000..9eb6f86 --- /dev/null +++ b/src/test/java/rife/bld/dependencies/AbstractVersionTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com) + * Licensed under the Apache License, Version 2.0 (the "License") + */ +package rife.bld.dependencies; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +abstract class AbstractVersionTest { + protected static final int X_LT_Y = -1; + protected static final int X_EQ_Y = 0; + protected static final int X_GT_Y = 1; + + protected abstract Version newVersion(String version); + + protected void assertOrder(int expected, String version1, String version2) { + Version v1 = newVersion(version1); + Version v2 = newVersion(version2); + + if (expected > 0) { + assertEquals(1, Integer.signum(v1.compareTo(v2)), "expected " + v1 + " > " + v2); + assertEquals(-1, Integer.signum(v2.compareTo(v1)), "expected " + v2 + " < " + v1); + assertNotEquals(v1, v2, "expected " + v1 + " != " + v2); + assertNotEquals(v2, v1, "expected " + v2 + " != " + v1); + } else if (expected < 0) { + assertEquals(-1, Integer.signum(v1.compareTo(v2)), "expected " + v1 + " < " + v2); + assertEquals(1, Integer.signum(v2.compareTo(v1)), "expected " + v2 + " > " + v1); + assertNotEquals(v1, v2, "expected " + v1 + " != " + v2); + assertNotEquals(v2, v1, "expected " + v2 + " != " + v1); + } else { + assertEquals(0, v1.compareTo(v2), "expected " + v1 + " == " + v2); + assertEquals(0, v2.compareTo(v1), "expected " + v2 + " == " + v1); + assertEquals(v1, v2, "expected " + v1 + " == " + v2); + assertEquals(v2, v1, "expected " + v2 + " == " + v1); + assertEquals(v1.hashCode(), v2.hashCode(), "expected #(" + v1 + ") == #(" + v1 + ")"); + } + } + + protected void assertSequence(String... versions) { + for (int i = 0; i < versions.length - 1; i++) { + for (int j = i + 1; j < versions.length; j++) { + assertOrder(X_LT_Y, versions[i], versions[j]); + } + } + } +} \ No newline at end of file diff --git a/src/test/java/rife/bld/dependencies/TestDependencyResolver.java b/src/test/java/rife/bld/dependencies/TestDependencyResolver.java index a2fc8ea..d4b9a96 100644 --- a/src/test/java/rife/bld/dependencies/TestDependencyResolver.java +++ b/src/test/java/rife/bld/dependencies/TestDependencyResolver.java @@ -134,6 +134,16 @@ public class TestDependencyResolver { assertEquals(0, dependencies.size()); } + @Test + void testGetCompileDependenciesGoogleApi() { + var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS), new Dependency("com.google.apis", "google-api-services-youtube", new VersionGeneric("v3-rev20240514-2.0.0"))); + var dependencies = resolver.getDirectDependencies(compile); + assertNotNull(dependencies); + assertEquals(1, dependencies.size()); + assertEquals(""" + com.google.api-client:google-api-client:2.5.0""", StringUtils.join(dependencies, "\n")); + } + @Test void testGetCompileDependenciesJetty() { var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))); @@ -850,6 +860,72 @@ public class TestDependencyResolver { } } + @Test + void testTransferDependencyGoogleApi() + throws Exception { + var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS), new Dependency("com.google.apis", "google-api-services-youtube", new VersionGeneric("v3-rev20240514-2.0.0"))); + var tmp = Files.createTempDirectory("transfers").toFile(); + try { + var result = resolver.getAllDependencies(compile).transferIntoDirectory(VersionResolution.dummy(), ArtifactRetriever.instance(), resolver.repositories(), tmp); + assertEquals(""" + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/apis/google-api-services-youtube/v3-rev20240514-2.0.0/google-api-services-youtube-v3-rev20240514-2.0.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/api-client/google-api-client/2.5.0/google-api-client-2.5.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/commons-codec/commons-codec/1.17.0/commons-codec-1.17.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/oauth-client/google-oauth-client/1.35.0/google-oauth-client-1.35.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.23.0/google-auth-library-credentials-1.23.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.23.0/google-auth-library-oauth2-http-1.23.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.44.1/google-http-client-gson-1.44.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/guava/guava/33.2.0-jre/guava-33.2.0-jre.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/http-client/google-http-client-apache-v2/1.44.1/google-http-client-apache-v2-1.44.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.44.1/google-http-client-1.44.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/auto/value/auto-value-annotations/1.10.4/auto-value-annotations-1.10.4.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.42.0/checker-qual-3.42.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/3.0.0/j2objc-annotations-3.0.0.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/io/grpc/grpc-context/1.60.1/grpc-context-1.60.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1.jar + https://repo1.maven.org/maven2/:https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1.jar""", StringUtils.join(result, "\n")); + + var files = FileUtils.getFileList(tmp); + assertEquals(24, files.size()); + Collections.sort(files); + assertEquals(""" + auto-value-annotations-1.10.4.jar + checker-qual-3.42.0.jar + commons-codec-1.17.0.jar + commons-logging-1.2.jar + error_prone_annotations-2.18.0.jar + failureaccess-1.0.2.jar + google-api-client-2.5.0.jar + google-api-services-youtube-v3-rev20240514-2.0.0.jar + google-auth-library-credentials-1.23.0.jar + google-auth-library-oauth2-http-1.23.0.jar + google-http-client-1.44.1.jar + google-http-client-apache-v2-1.44.1.jar + google-http-client-gson-1.44.1.jar + google-oauth-client-1.35.0.jar + grpc-context-1.60.1.jar + gson-2.10.1.jar + guava-33.2.0-jre.jar + httpclient-4.5.14.jar + httpcore-4.4.16.jar + j2objc-annotations-3.0.0.jar + jsr305-3.0.2.jar + listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar + opencensus-api-0.31.1.jar + opencensus-contrib-http-util-0.31.1.jar""", StringUtils.join(files, "\n")); + } finally { + FileUtils.deleteDirectory(tmp); + } + } + @Test void testTransferDependencyJettyOverriddenVersions() throws Exception { diff --git a/src/test/java/rife/bld/dependencies/TestVersionGeneric.java b/src/test/java/rife/bld/dependencies/TestVersionGeneric.java new file mode 100644 index 0000000..c51c767 --- /dev/null +++ b/src/test/java/rife/bld/dependencies/TestVersionGeneric.java @@ -0,0 +1,585 @@ +/* + * Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com) + * Licensed under the Apache License, Version 2.0 (the "License") + */ +package rife.bld.dependencies; + +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.Assertions.*; + +// https://github.com/apache/maven-resolver/blob/98126539f3c66fc4ab50b178c2eb4b8fd169fd72/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/VersionGenericTest.java +public class TestVersionGeneric extends AbstractVersionTest { + + protected Version newVersion(String version) { + return new VersionGeneric(version); + } + + @Test + void testEmptyVersion() { + assertOrder(X_EQ_Y, "0", ""); + } + + // Block of tests from https://issues.apache.org/jira/browse/MRESOLVER-336 + @Test + void testTrimPadding() { + // 1.0.0 -> 1 + List items = new ArrayList<>(Arrays.asList( + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 1), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0))); + assertEquals(3, items.size()); + VersionGeneric.trimPadding(items); + assertEquals(1, items.size()); + } + + @Test + void testTrimPaddingNotNeededString() { + // 1.0.0.string -> 1.string + List items = new ArrayList<>(Arrays.asList( + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 1), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_STRING, "string"))); + assertEquals(4, items.size()); + VersionGeneric.trimPadding(items); + assertEquals(2, items.size()); + } + + @Test + void testTrimPaddingNeededQualifier() { + // 1.0.0.ga -> 1 + List items = new ArrayList<>(Arrays.asList( + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 1), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_QUALIFIER, 0))); + assertEquals(4, items.size()); + VersionGeneric.trimPadding(items); + assertEquals(1, items.size()); + } + + @Test + void testTrimPaddingNeededQualifierMixed() { + // 1.0.0.string.0.ga -> 1.string + List items = new ArrayList<>(Arrays.asList( + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 1), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_STRING, "string"), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_QUALIFIER, 0))); + assertEquals(6, items.size()); + VersionGeneric.trimPadding(items); + assertEquals(2, items.size()); + } + + @Test + void testTrimPaddingNeededQualifierMixedInBetweenGa() { + // 1.0.ga.0.string.0.ga -> 1.ga.0.string + List items = new ArrayList<>(Arrays.asList( + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 1), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_QUALIFIER, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_STRING, "string"), + new VersionGeneric.Item(VersionGeneric.Item.KIND_INT, 0), + new VersionGeneric.Item(VersionGeneric.Item.KIND_QUALIFIER, 0))); + assertEquals(7, items.size()); + VersionGeneric.trimPadding(items); + assertEquals(4, items.size()); + } + + @Test + void testEdgeCase_1_1() { + Version v1 = newVersion("0.0.0.ga.ga.foo"); + Version v2 = newVersion("foo"); + // they were equal in Resolver 1.x + assertNotEquals(v1, v2); + } + + @Test + void testEdgeCase_1_2() { + // as expected + assertOrder(X_LT_Y, "ga.ga.foo", "foo"); + } + + @Test + void testEdgeCase_2_1() { + assertOrder(X_GT_Y, "0.foo.1.2.3", "foo.1.2.3"); + // they were equal in Resolver 1.x + assertOrder(X_GT_Y, "0.foo", "foo"); + assertOrder(X_EQ_Y, "1.0.0-foo", "1-foo"); + // but "foo" != "ga" (string > qualifier) + assertOrder(X_LT_Y, "1.0.0-ga-foo", "1-foo"); + assertOrder(X_EQ_Y, "1.0.0-ga-foo", "1-ga-foo"); + assertOrder(X_LT_Y, "1.0.0.final-foo", "1-foo"); + assertOrder(X_EQ_Y, "1.0.0.final-foo", "1-final-foo"); + } + + @Test + void testEdgeCase_2_2() { + Version v1 = newVersion("0.0.0.ga.ga.foo"); + Version v2 = newVersion("foo"); + Version v3 = newVersion("0.0.0.0.0.foo"); + // they were equal in Resolver 1.x + assertNotEquals(v1, v2); + // they were equal in Resolver 1.x + assertNotEquals(v2, v3); + // but "0" != "ga" + assertNotEquals(v1, v3); + } + + @Test + void testEdgeCase_2_3() { + // 1.ga trimmed to 1 == 1.0.0.0.0.0... + assertOrder(X_EQ_Y, "1.ga", "1.0"); + // ga.1 is not trimmed < 0.1 (as qualifier < number) + assertOrder(X_LT_Y, "ga.1", "0.1"); + // 1.ga.1 is not trimmed < 1.0.1 (as qualifier < number) + assertOrder(X_LT_Y, "1.ga.1", "1.0.1"); + } + + @Test + void testEdgeCase_2_4() { + assertOrder(X_LT_Y, "1.0.final.1", "1.0.1.final"); + } + + @Test + void testQualifier() { + String ver = "1.0.0"; + assertOrder(X_LT_Y, ver + ".a1", ver + ".b1"); + assertOrder(X_LT_Y, ver + ".b1", ver + ".m1"); + assertOrder(X_LT_Y, ver + ".m1", ver + ".rc"); + assertOrder(X_LT_Y, ver + ".rc", ver + "-SNAPSHOT"); + assertOrder(X_LT_Y, ver + "-SNAPSHOT", ver); + assertOrder(X_EQ_Y, ver + ".ga", ver + ".final"); + assertOrder(X_EQ_Y, ver + ".final", ver + ".release"); + assertOrder(X_LT_Y, ver + ".final", ver + ".sp"); + assertOrder(X_LT_Y, ver, ver + ".sp"); + } + + @Test + void testTransition() { + VersionGeneric v; + v = (VersionGeneric) newVersion("1.0.0"); + assertEquals(1, v.asItems().size()); // trailing zero padding trimmed + v = (VersionGeneric) newVersion("1.2.3"); + assertEquals(3, v.asItems().size()); + v = (VersionGeneric) newVersion("1a0"); + assertEquals(2, v.asItems().size()); // trailing zero padding trimmed + v = (VersionGeneric) newVersion("1a2"); + assertEquals(3, v.asItems().size()); // trailing zero padding trimmed + } + + // End of https://issues.apache.org/jira/browse/MRESOLVER-336 + + @Test + void testNumericOrdering() { + assertOrder(X_LT_Y, "2", "10"); + assertOrder(X_LT_Y, "1.2", "1.10"); + assertOrder(X_LT_Y, "1.0.2", "1.0.10"); + assertOrder(X_LT_Y, "1.0.0.2", "1.0.0.10"); + assertOrder(X_LT_Y, "1.0.20101206.111434.1", "1.0.20101206.111435.1"); + assertOrder(X_LT_Y, "1.0.20101206.111434.2", "1.0.20101206.111434.10"); + } + + @Test + void testDelimiters() { + assertOrder(X_EQ_Y, "1.0", "1-0"); + assertOrder(X_EQ_Y, "1.0", "1_0"); + assertOrder(X_EQ_Y, "1.a", "1a"); + } + + @Test + void testLeadingZerosAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "01"); + assertOrder(X_EQ_Y, "1.2", "1.002"); + assertOrder(X_EQ_Y, "1.2.3", "1.2.0003"); + assertOrder(X_EQ_Y, "1.2.3.4", "1.2.3.00004"); + } + + @Test + void testTrailingZerosAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0"); + assertOrder(X_EQ_Y, "1", "1-0-0-0-0-0-0-0-0-0-0-0-0-0"); + assertOrder(X_EQ_Y, "1", "1.0-0.0-0.0-0.0-0.0-0.0-0.0"); + assertOrder(X_EQ_Y, "1", "1.0000000000000"); + assertOrder(X_EQ_Y, "1.0", "1.0.0"); + } + + @Test + void testTrailingZerosBeforeQualifierAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1.0-ga", "1.0.0-ga"); + assertOrder(X_EQ_Y, "1.0.ga", "1.0.0.ga"); + assertOrder(X_EQ_Y, "1.0ga", "1.0.0ga"); + + assertOrder(X_EQ_Y, "1.0-alpha", "1.0.0-alpha"); + assertOrder(X_EQ_Y, "1.0.alpha", "1.0.0.alpha"); + assertOrder(X_EQ_Y, "1.0alpha", "1.0.0alpha"); + assertOrder(X_EQ_Y, "1.0-alpha-snapshot", "1.0.0-alpha-snapshot"); + assertOrder(X_EQ_Y, "1.0.alpha.snapshot", "1.0.0.alpha.snapshot"); + + assertOrder(X_EQ_Y, "1.x.0-alpha", "1.x.0.0-alpha"); + assertOrder(X_EQ_Y, "1.x.0.alpha", "1.x.0.0.alpha"); + assertOrder(X_EQ_Y, "1.x.0-alpha-snapshot", "1.x.0.0-alpha-snapshot"); + assertOrder(X_EQ_Y, "1.x.0.alpha.snapshot", "1.x.0.0.alpha.snapshot"); + } + + @Test + void testTrailingDelimitersAreSemanticallyIrrelevant() { + assertOrder(X_EQ_Y, "1", "1............."); + assertOrder(X_EQ_Y, "1", "1-------------"); + assertOrder(X_EQ_Y, "1.0", "1............."); + assertOrder(X_EQ_Y, "1.0", "1-------------"); + } + + @Test + void testInitialDelimiters() { + assertOrder(X_EQ_Y, "0.1", ".1"); + assertOrder(X_EQ_Y, "0.0.1", "..1"); + assertOrder(X_EQ_Y, "0.1", "-1"); + assertOrder(X_EQ_Y, "0.0.1", "--1"); + } + + @Test + void testConsecutiveDelimiters() { + assertOrder(X_EQ_Y, "1.0.1", "1..1"); + assertOrder(X_EQ_Y, "1.0.0.1", "1...1"); + assertOrder(X_EQ_Y, "1.0.1", "1--1"); + assertOrder(X_EQ_Y, "1.0.0.1", "1---1"); + } + + @Test + void testUnlimitedNumberOfVersionComponents() { + assertOrder(X_GT_Y, "1.0.1.2.3.4.5.6.7.8.9.0.1.2.10", "1.0.1.2.3.4.5.6.7.8.9.0.1.2.3"); + } + + @Test + void testUnlimitedNumberOfDigitsInNumericComponent() { + assertOrder(X_GT_Y, "1.1234567890123456789012345678901", "1.123456789012345678901234567891"); + } + + @Test + void testTransitionFromDigitToLetterAndViceVersaIsEqualivantToDelimiter() { + assertOrder(X_EQ_Y, "1alpha10", "1.alpha.10"); + assertOrder(X_EQ_Y, "1alpha10", "1-alpha-10"); + + assertOrder(X_GT_Y, "1.alpha10", "1.alpha2"); + assertOrder(X_GT_Y, "10alpha", "1alpha"); + } + + @Test + void testWellKnownQualifierOrdering() { + assertOrder(X_EQ_Y, "1-alpha1", "1-a1"); + assertOrder(X_LT_Y, "1-alpha", "1-beta"); + assertOrder(X_EQ_Y, "1-beta1", "1-b1"); + assertOrder(X_LT_Y, "1-beta", "1-milestone"); + assertOrder(X_EQ_Y, "1-milestone1", "1-m1"); + assertOrder(X_LT_Y, "1-milestone", "1-rc"); + assertOrder(X_EQ_Y, "1-rc", "1-cr"); + assertOrder(X_LT_Y, "1-rc", "1-snapshot"); + assertOrder(X_LT_Y, "1-snapshot", "1"); + assertOrder(X_EQ_Y, "1", "1-ga"); + assertOrder(X_EQ_Y, "1", "1.ga.0.ga"); + assertOrder(X_EQ_Y, "1.0", "1-ga"); + assertOrder(X_EQ_Y, "1", "1-ga.ga"); + assertOrder(X_EQ_Y, "1", "1-ga-ga"); + assertOrder(X_EQ_Y, "A", "A.ga.ga"); + assertOrder(X_EQ_Y, "A", "A-ga-ga"); + assertOrder(X_EQ_Y, "1", "1-final"); + assertOrder(X_EQ_Y, "1", "1-release"); + assertOrder(X_LT_Y, "1", "1-sp"); + + assertOrder(X_LT_Y, "A.rc.1", "A.ga.1"); + assertOrder(X_GT_Y, "A.sp.1", "A.ga.1"); + assertOrder(X_LT_Y, "A.rc.x", "A.ga.x"); + assertOrder(X_GT_Y, "A.sp.x", "A.ga.x"); + } + + @Test + void testWellKnownQualifierVersusUnknownQualifierOrdering() { + assertOrder(X_GT_Y, "1-abc", "1-alpha"); + assertOrder(X_GT_Y, "1-abc", "1-beta"); + assertOrder(X_GT_Y, "1-abc", "1-milestone"); + assertOrder(X_GT_Y, "1-abc", "1-rc"); + assertOrder(X_GT_Y, "1-abc", "1-snapshot"); + assertOrder(X_GT_Y, "1-abc", "1"); + assertOrder(X_GT_Y, "1-abc", "1-sp"); + } + + @Test + void testWellKnownSingleCharQualifiersOnlyRecognizedIfImmediatelyFollowedByNumber() { + assertOrder(X_GT_Y, "1.0a", "1.0"); + assertOrder(X_GT_Y, "1.0-a", "1.0"); + assertOrder(X_GT_Y, "1.0.a", "1.0"); + assertOrder(X_GT_Y, "1.0b", "1.0"); + assertOrder(X_GT_Y, "1.0-b", "1.0"); + assertOrder(X_GT_Y, "1.0.b", "1.0"); + assertOrder(X_GT_Y, "1.0m", "1.0"); + assertOrder(X_GT_Y, "1.0-m", "1.0"); + assertOrder(X_GT_Y, "1.0.m", "1.0"); + + assertOrder(X_LT_Y, "1.0a1", "1.0"); + assertOrder(X_LT_Y, "1.0-a1", "1.0"); + assertOrder(X_LT_Y, "1.0.a1", "1.0"); + assertOrder(X_LT_Y, "1.0b1", "1.0"); + assertOrder(X_LT_Y, "1.0-b1", "1.0"); + assertOrder(X_LT_Y, "1.0.b1", "1.0"); + assertOrder(X_LT_Y, "1.0m1", "1.0"); + assertOrder(X_LT_Y, "1.0-m1", "1.0"); + assertOrder(X_LT_Y, "1.0.m1", "1.0"); + + assertOrder(X_GT_Y, "1.0a.1", "1.0"); + assertOrder(X_GT_Y, "1.0a-1", "1.0"); + assertOrder(X_GT_Y, "1.0b.1", "1.0"); + assertOrder(X_GT_Y, "1.0b-1", "1.0"); + assertOrder(X_GT_Y, "1.0m.1", "1.0"); + assertOrder(X_GT_Y, "1.0m-1", "1.0"); + } + + @Test + void testUnknownQualifierOrdering() { + assertOrder(X_LT_Y, "1-abc", "1-abcd"); + assertOrder(X_LT_Y, "1-abc", "1-bcd"); + assertOrder(X_GT_Y, "1-abc", "1-aac"); + } + + @Test + void testCaseInsensitiveOrderingOfQualifiers() { + assertOrder(X_EQ_Y, "1.alpha", "1.ALPHA"); + assertOrder(X_EQ_Y, "1.alpha", "1.Alpha"); + + assertOrder(X_EQ_Y, "1.beta", "1.BETA"); + assertOrder(X_EQ_Y, "1.beta", "1.Beta"); + + assertOrder(X_EQ_Y, "1.milestone", "1.MILESTONE"); + assertOrder(X_EQ_Y, "1.milestone", "1.Milestone"); + + assertOrder(X_EQ_Y, "1.rc", "1.RC"); + assertOrder(X_EQ_Y, "1.rc", "1.Rc"); + assertOrder(X_EQ_Y, "1.cr", "1.CR"); + assertOrder(X_EQ_Y, "1.cr", "1.Cr"); + + assertOrder(X_EQ_Y, "1.snapshot", "1.SNAPSHOT"); + assertOrder(X_EQ_Y, "1.snapshot", "1.Snapshot"); + + assertOrder(X_EQ_Y, "1.ga", "1.GA"); + assertOrder(X_EQ_Y, "1.ga", "1.Ga"); + assertOrder(X_EQ_Y, "1.final", "1.FINAL"); + assertOrder(X_EQ_Y, "1.final", "1.Final"); + assertOrder(X_EQ_Y, "1.release", "1.RELEASE"); + assertOrder(X_EQ_Y, "1.release", "1.Release"); + + assertOrder(X_EQ_Y, "1.sp", "1.SP"); + assertOrder(X_EQ_Y, "1.sp", "1.Sp"); + + assertOrder(X_EQ_Y, "1.unknown", "1.UNKNOWN"); + assertOrder(X_EQ_Y, "1.unknown", "1.Unknown"); + } + + @Test + void testCaseInsensitiveOrderingOfQualifiersIsLocaleIndependent() { + Locale orig = Locale.getDefault(); + try { + Locale[] locales = {Locale.ENGLISH, new Locale("tr")}; + for (Locale locale : locales) { + Locale.setDefault(locale); + assertOrder(X_EQ_Y, "1-abcdefghijklmnopqrstuvwxyz", "1-ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + } finally { + Locale.setDefault(orig); + } + } + + @Test + void testQualifierVersusNumberOrdering() { + assertOrder(X_LT_Y, "1-ga", "1-1"); + assertOrder(X_LT_Y, "1.ga", "1.1"); + assertOrder(X_EQ_Y, "1-ga", "1.0"); + assertOrder(X_EQ_Y, "1.ga", "1.0"); + + assertOrder(X_LT_Y, "1-ga-1", "1-0-1"); + assertOrder(X_LT_Y, "1.ga.1", "1.0.1"); + + assertOrder(X_GT_Y, "1.sp", "1.0"); + assertOrder(X_LT_Y, "1.sp", "1.1"); + + assertOrder(X_LT_Y, "1-abc", "1-1"); + assertOrder(X_LT_Y, "1.abc", "1.1"); + + assertOrder(X_LT_Y, "1-xyz", "1-1"); + assertOrder(X_LT_Y, "1.xyz", "1.1"); + } + + @Test + void testVersionEvolution() { + assertSequence( + "0.9.9-SNAPSHOT", + "0.9.9", + "0.9.10-SNAPSHOT", + "0.9.10", + "1.0-alpha-2-SNAPSHOT", + "1.0-alpha-2", + "1.0-alpha-10-SNAPSHOT", + "1.0-alpha-10", + "1.0-beta-1-SNAPSHOT", + "1.0-beta-1", + "1.0-rc-1-SNAPSHOT", + "1.0-rc-1", + "1.0-SNAPSHOT", + "1.0", + "1.0-sp-1-SNAPSHOT", + "1.0-sp-1", + "1.0.1-alpha-1-SNAPSHOT", + "1.0.1-alpha-1", + "1.0.1-beta-1-SNAPSHOT", + "1.0.1-beta-1", + "1.0.1-rc-1-SNAPSHOT", + "1.0.1-rc-1", + "1.0.1-SNAPSHOT", + "1.0.1", + "1.1-SNAPSHOT", + "1.1"); + + assertSequence("1.0-alpha", "1.0", "1.0-1"); + assertSequence("1.0.alpha", "1.0", "1.0-1"); + assertSequence("1.0-alpha", "1.0", "1.0.1"); + assertSequence("1.0.alpha", "1.0", "1.0.1"); + } + + @Test + void testMinimumSegment() { + assertOrder(X_LT_Y, "1.min", "1.0-alpha-1"); + assertOrder(X_LT_Y, "1.min", "1.0-SNAPSHOT"); + assertOrder(X_LT_Y, "1.min", "1.0"); + assertOrder(X_LT_Y, "1.min", "1.9999999999"); + + assertOrder(X_EQ_Y, "1.min", "1.MIN"); + + assertOrder(X_GT_Y, "1.min", "0.99999"); + assertOrder(X_GT_Y, "1.min", "0.max"); + } + + @Test + void testMaximumSegment() { + assertOrder(X_GT_Y, "1.max", "1.0-alpha-1"); + assertOrder(X_GT_Y, "1.max", "1.0-SNAPSHOT"); + assertOrder(X_GT_Y, "1.max", "1.0"); + assertOrder(X_GT_Y, "1.max", "1.9999999999"); + + assertOrder(X_EQ_Y, "1.max", "1.MAX"); + + assertOrder(X_LT_Y, "1.max", "2.0-alpha-1"); + assertOrder(X_LT_Y, "1.max", "2.min"); + } + + /** + * UT for MRESOLVER-314. + * + * Generates random UUID string based versions and tries to sort them. While this test is not as reliable + * as {@link #testCompareUuidVersionStringStream()}, it covers broader range and in case it fails it records + * the failed array, so we can investigate more. + */ + @Test + void testCompareUuidRandom() { + for (int j = 0; j < 32; j++) { + ArrayList versions = new ArrayList<>(); + for (int i = 0; i < 64; i++) { + versions.add(newVersion(UUID.randomUUID().toString())); + } + try { + Collections.sort(versions); + } catch (Exception e) { + e.printStackTrace(System.err); + System.err.println("The UUIDs used"); + System.err.println(versions.stream().map(Version::toString).collect(Collectors.joining("\n"))); + fail("unexpected exception"); + } + } + } + + /** + * UT for MRESOLVER-314. + * + * Works on known set that failed before fix, provided by {@link #uuidVersionStringStream()}. + */ + @Test + void testCompareUuidVersionStringStream() { + // this operation below fails with IAEx if comparison is unstable + uuidVersionStringStream().map(this::newVersion).sorted().collect(toList()); + } + + private Stream uuidVersionStringStream() { + return Stream.of( + "e3f6b227-e09d-4461-a030-b8c1755834f7", + "dfdf5e15-b047-4fee-94e5-3ddf6fe90a0c", + "bcc15412-6817-4b64-acef-169d048626f6", + "76093f07-ab1c-4cdd-ae92-9bb500ceed84", + "7ca8dc9f-4e73-459b-8f30-06aa7972f486", + "93fee46b-2715-4abd-877a-4197eb8601aa", + "0379da36-84ee-4d06-9388-83d3aa6536b5", + "4bb2c7a8-cf68-4ca5-8024-72dc93506da9", + "9dcc4cd1-34d2-4499-8dab-3ef8bca9680d", + "ea53d552-83ab-4f7d-852d-98951201083d", + "0bc420d2-4089-468b-bc54-0a4e2835feed", + "318d2433-fe40-4f28-9f3a-4e3d66d9b5fb", + "447b456c-81a4-4f24-9d2e-e5091c39cd19", + "85741f6e-26fe-40d0-a73a-283315409ab2", + "3165b9b2-9f8e-4117-ac70-87056eb45745", + "9d534bf3-a3b0-4a19-9809-670934c10752", + "86d78bba-d84e-4349-aea6-850721e78188", + "06392b8c-e26c-4a83-8ec2-085415bc513d", + "1fb13754-90be-42cb-bc7f-9b9211494e92", + "3018965c-3330-402a-8075-caa7613ec4fa", + "7ecc912b-4938-4411-895e-8ca7cf22ce02", + "6580ada2-4764-45a2-9789-98217d7cf5b6", + "be9d0de4-4ba7-4fdd-8f76-cb579168c549", + "7a8236d6-6bec-4176-b6a1-f869c02183c3", + "089f4195-881c-4f9e-8bc1-124531dee977", + "46ffda62-768a-4864-9581-cc75eafe1a67", + "1d6226f6-dacc-42a9-bd88-7aab1f59df74", + "0948ed55-c25e-4319-9801-5f817bac09b5", + "2fd52f5e-b856-47ad-9e58-45c1d0ba437b", + "6c325bd0-ac6b-4391-a5c5-caa160972fa2", + "d213f6be-f56b-42d2-abda-4300742e0add", + "efaae115-cc21-4b2e-a150-fb4e0d807736", + "30f872e8-9cb5-4b22-b65c-6819ca7a14ba", + "d8e5fb54-6e90-4f74-adb3-451abfbe76a8", + "b47d62b8-9256-47a1-8e21-21ba9639c212", + "b25da555-e1f7-4bc5-92fe-4c895d9c70d8", + "088f0de7-5973-4c10-a7ff-9f3cd7718572", + "b161de76-e5d5-4224-883b-a749b147d63d", + "19b7de96-09fa-4276-843d-c0fbdaf07767", + "e0503f73-33fd-4f9c-812f-8cae3a128c28", + "b8c57488-a42c-43ed-bfb9-acd112d6b68f", + "25997299-0825-4c9b-b0ed-75f935c63fd7", + "2b2e2fcd-3988-45af-855b-7646c0cdbfb5", + "4e6e16b9-2ae4-4593-b907-1febaf3988dc", + "ac8bd519-7fd4-4b85-8154-9dbb87f6cd4f", + "61473b39-b620-468b-abcf-16fe6adfd5cb", + "18e7a548-3f0b-492b-bc19-dce3eec736fa", + "c4d82839-3c46-4eff-b10c-ec0b5bcc600b", + "48f6e90f-924b-4859-9763-3ffe661f5af6", + "48852d79-ba23-475e-b675-a413b989a2a7", + "f7ee0915-ff00-4404-9e9a-6e753d5ff767", + "d6462359-a4e2-45ab-aedc-3b1849b0e6ca", + "e66228de-d1ed-4973-a108-c181d5059fdb", + "d49672a7-177d-475d-aad0-aab0ff4a11b7", + "bfa9337a-0489-4cba-b2db-e0d9d2424e4f", + "dc9bbe34-3c54-4c0f-a3cd-00e96604ae23", + "a8119cf1-9694-4b24-923a-3fc729b5f809", + "5d29cf45-3b9c-4697-85b8-86c81c6ec0c9", + "e3dcb4c2-a867-40f7-a3b1-fb1058a041e5", + "ae240754-2ea2-409a-a92c-648fc7a7b70b", + "8c187383-d59b-4e49-8dfd-98aa5f01925a", + "9b100ee6-71ed-4746-92c2-b5fb02af7ebd", + "f95e94f7-2443-4b2f-a10d-059d8d224dd9", + "b558af80-78bc-43c7-b916-d635a23cc4b5"); + } +} diff --git a/src/test/java/rife/bld/dependencies/TestVersionNumber.java b/src/test/java/rife/bld/dependencies/TestVersionNumber.java index 60b389f..ee133f4 100644 --- a/src/test/java/rife/bld/dependencies/TestVersionNumber.java +++ b/src/test/java/rife/bld/dependencies/TestVersionNumber.java @@ -70,16 +70,16 @@ public class TestVersionNumber { void testInvalidParsed() { assertEquals(VersionNumber.parse(null), VersionNumber.UNKNOWN); assertEquals(VersionNumber.parse(""), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("foo"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("1."), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("1.2.3-"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("."), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("_"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("-"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse(".1"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("a.1"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("1_2"), VersionNumber.UNKNOWN); - assertEquals(VersionNumber.parse("1_2_2"), VersionNumber.UNKNOWN); + assertEquals(VersionNumber.parse("foo"), new VersionGeneric("foo")); + assertEquals(VersionNumber.parse("1."), new VersionGeneric("1.")); + assertEquals(VersionNumber.parse("1.2.3-"), new VersionGeneric("1.2.3-")); + assertEquals(VersionNumber.parse("."), new VersionGeneric(".")); + assertEquals(VersionNumber.parse("_"), new VersionGeneric("_")); + assertEquals(VersionNumber.parse("-"), new VersionGeneric("-")); + assertEquals(VersionNumber.parse(".1"), new VersionGeneric(".1")); + assertEquals(VersionNumber.parse("a.1"), new VersionGeneric("a.1")); + assertEquals(VersionNumber.parse("1_2"), new VersionGeneric("1_2")); + assertEquals(VersionNumber.parse("1_2_2"), new VersionGeneric("1_2_2")); } @Test