From 589cde44fc5b9b1e55a60c2fcb0a725b4dd92d9d Mon Sep 17 00:00:00 2001 From: Viktor De Pasquale Date: Wed, 5 May 2021 13:53:38 +0200 Subject: [PATCH] Updated versioning to provide VersionCode instead of integer That way comparisons through semver are possible to the point where all digits are actually in the constraints of java integers --- src/main/kotlin/dev/chainmail/taggy/Helper.kt | 4 ++ .../kotlin/dev/chainmail/taggy/pattern/Tag.kt | 19 +---- .../chainmail/taggy/pattern/VersionCode.kt | 53 ++++++++++++++ .../taggy/pattern/VersionCodeTest.kt | 71 +++++++++++++++++++ .../kotlin/dev/chainmail/taggy/placeholder | 0 5 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/dev/chainmail/taggy/Helper.kt create mode 100644 src/main/kotlin/dev/chainmail/taggy/pattern/VersionCode.kt create mode 100644 src/test/kotlin/dev/chainmail/taggy/pattern/VersionCodeTest.kt create mode 100644 src/test/kotlin/dev/chainmail/taggy/placeholder diff --git a/src/main/kotlin/dev/chainmail/taggy/Helper.kt b/src/main/kotlin/dev/chainmail/taggy/Helper.kt new file mode 100644 index 0000000..9f7d899 --- /dev/null +++ b/src/main/kotlin/dev/chainmail/taggy/Helper.kt @@ -0,0 +1,4 @@ +package dev.chainmail.taggy + +val characters = Regex("[a-zA-Z]+") +val numbers = Regex("[0-9]+") \ No newline at end of file diff --git a/src/main/kotlin/dev/chainmail/taggy/pattern/Tag.kt b/src/main/kotlin/dev/chainmail/taggy/pattern/Tag.kt index a49b871..4bd7f71 100644 --- a/src/main/kotlin/dev/chainmail/taggy/pattern/Tag.kt +++ b/src/main/kotlin/dev/chainmail/taggy/pattern/Tag.kt @@ -1,7 +1,7 @@ package dev.chainmail.taggy.pattern -import kotlin.math.abs -import kotlin.math.log10 +import dev.chainmail.taggy.characters +import dev.chainmail.taggy.numbers @Suppress("DataClassPrivateConstructor") data class Tag( @@ -10,17 +10,7 @@ data class Tag( val separator: String ) { - val code: Int = name.splitToSequence('.') - .map { it.replace(characters, "").toInt() } - .reduce { acc, it -> - val multiplier = when (it) { - // just multiply the acc value by 10 - 0 -> 1.0 - // calculate number of digits in this number and multiply it by 10 - else -> log10(abs(it).toDouble()) + 1 - }.toInt() * 10 - acc * multiplier + it - } + val code = VersionCode(name, postfix) fun postfixHasNumbers() = postfix?.contains(numbers) == true @@ -71,9 +61,6 @@ data class Tag( companion object { - private val characters = Regex("[a-zA-Z]+") - private val numbers = Regex("[0-9]+") - fun from(tag: String, postfix: String?, separator: String): Tag { if ( tag.contains(separator) && diff --git a/src/main/kotlin/dev/chainmail/taggy/pattern/VersionCode.kt b/src/main/kotlin/dev/chainmail/taggy/pattern/VersionCode.kt new file mode 100644 index 0000000..22b2675 --- /dev/null +++ b/src/main/kotlin/dev/chainmail/taggy/pattern/VersionCode.kt @@ -0,0 +1,53 @@ +package dev.chainmail.taggy.pattern + +import dev.chainmail.taggy.characters +import kotlin.math.max + +class VersionCode( + version: String, + postfix: String? +) : Comparable { + + private val segments = version.splitToSequence(".") + .map { it.replace(characters, "").toInt() } + .toList() + + private val revision = postfix + ?.replace(characters, "") + ?.toIntOrNull() + + override operator fun compareTo(other: VersionCode): Int { + if (this === other) { + return 0 + } + + val segmentCount = max( + segments.size, + other.segments.size + ) + + // loop through all the segments to establish which of these versions is higher + for (i in 0 until segmentCount) { + val my = segments.getOrElse(i) { 0 } + val their = other.segments.getOrElse(i) { 0 } + + return when { + my > their -> 1 + my < their -> -1 + else -> continue + } + } + + // if the versions are identical, then we check for revisions + val my = revision ?: Int.MAX_VALUE + val their = other.revision ?: Int.MAX_VALUE + + return my - their + } + + override fun equals(other: Any?): Boolean { + if (other !is VersionCode) return false + return compareTo(other) == 0 + } + +} \ No newline at end of file diff --git a/src/test/kotlin/dev/chainmail/taggy/pattern/VersionCodeTest.kt b/src/test/kotlin/dev/chainmail/taggy/pattern/VersionCodeTest.kt new file mode 100644 index 0000000..1ecfb6c --- /dev/null +++ b/src/test/kotlin/dev/chainmail/taggy/pattern/VersionCodeTest.kt @@ -0,0 +1,71 @@ +package dev.chainmail.taggy.pattern + +import org.junit.Test +import kotlin.test.assertTrue + +class VersionCodeTest { + + private fun testComparison( + old: String, + new: String, + postfix: String? = null, + separator: String = "-" + ) { + val contenderOld = Tag.from(old, postfix, separator) + val contenderNew = Tag.from(new, postfix, separator) + assertTrue("Codes do not properly handle semantic versioning. $new is newer than $old") { + contenderNew.code > contenderOld.code + } + } + + @Test + fun semanticComparison() { + testComparison(old = "1.193.0", new = "2.0.0") + } + + @Test + fun semanticUnilateralPostfixComparison() { + testComparison(old = "1.193.0-dev1", new = "1.193.0", postfix = "dev") + } + + @Test + fun semanticBilateralPostfixComparison() { + testComparison(old = "1.193.0-dev1", new = "1.193.0-dev2", postfix = "dev") + } + + @Test + fun semanticUnilateralStagePostfixComparison() { + testComparison(old = "1.193.0", new = "1.193.1-dev1", postfix = "dev") + } + + // --- + + private fun testEquality( + old: String, + new: String, + postfix: String? = null, + separator: String = "-" + ) { + val contenderOld = Tag.from(old, postfix, separator) + val contenderNew = Tag.from(new, postfix, separator) + assertTrue("Codes do not properly handle semantic versioning. $new is not equal to $old") { + contenderNew.code == contenderOld.code + } + } + + @Test + fun semanticEquality() { + testEquality(old = "1.0.0", new = "1.0.0") + } + + @Test(expected = AssertionError::class) + fun semanticFailUnilateralPostfixEquality() { + testEquality(old = "1.0.0-dev30", new = "1.0.0", postfix = "dev") + } + + @Test(expected = AssertionError::class) + fun semanticFailBilateralPostfixEquality() { + testEquality(old = "1.0.0-dev1", new = "1.0.0-dev2", postfix = "dev") + } + +} \ No newline at end of file diff --git a/src/test/kotlin/dev/chainmail/taggy/placeholder b/src/test/kotlin/dev/chainmail/taggy/placeholder new file mode 100644 index 0000000..e69de29