mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Sem Version (#164)
* Sem Version * Review: Add missing logic * Review code - Removed @JvmField - Comments - Fix Compare Logic - Add tests from SemVer.org * Deleted redundant statement * Rename RangeChecker to RangeRequirement * Code Review - Move SemVersion#compareTo to SemVersionInternal#compareInternal - Move top-level functions to companion object - Make SemVersion comparable * KDoc * Update KDoc; fix parseRangeRequirement * Update KDoc * Update comment * Update KDoc * Update KDoc * Typo * Typo
This commit is contained in:
parent
466b067d9f
commit
dc81835b68
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.internal.util
|
||||
|
||||
import net.mamoe.mirai.console.util.SemVersion
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@Suppress("RegExpRedundantEscape")
|
||||
internal object SemVersionInternal {
|
||||
private val directVersion = """^[0-9]+(\.[0-9]+)+(|[\-+].+)$""".toRegex()
|
||||
private val versionSelect = """^[0-9]+(\.[0-9]+)*\.x$""".toRegex()
|
||||
private val versionRange = """([0-9]+(\.[0-9]+)+(|[\-+].+))\s*\-\s*([0-9]+(\.[0-9]+)+(|[\-+].+))""".toRegex()
|
||||
private val versionMathRange =
|
||||
"""\[([0-9]+(\.[0-9]+)+(|[\-+].+))\s*\,\s*([0-9]+(\.[0-9]+)+(|[\-+].+))\]""".toRegex()
|
||||
private val versionRule = """^((\>\=)|(\<\=)|(\=)|(\>)|(\<))\s*([0-9]+(\.[0-9]+)+(|[\-+].+))$""".toRegex()
|
||||
private fun Collection<*>.dump() {
|
||||
forEachIndexed { index, value ->
|
||||
println("$index, $value")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun String.parseRule(): SemVersion.RangeRequirement {
|
||||
val trimmed = trim()
|
||||
if (directVersion.matches(trimmed)) {
|
||||
val parsed = SemVersion.parse(trimmed)
|
||||
return SemVersion.RangeRequirement {
|
||||
it.compareTo(parsed) == 0
|
||||
}
|
||||
}
|
||||
if (versionSelect.matches(trimmed)) {
|
||||
val regex = ("^" +
|
||||
trimmed.replace(".", "\\.")
|
||||
.replace("x", ".+") +
|
||||
"$"
|
||||
).toRegex()
|
||||
return SemVersion.RangeRequirement {
|
||||
regex.matches(it.toString())
|
||||
}
|
||||
}
|
||||
(versionRange.matchEntire(trimmed) ?: versionMathRange.matchEntire(trimmed))?.let { range ->
|
||||
var start = SemVersion.parse(range.groupValues[1])
|
||||
var end = SemVersion.parse(range.groupValues[4])
|
||||
if (start > end) {
|
||||
val c = end
|
||||
end = start
|
||||
start = c
|
||||
}
|
||||
val compareRange = start..end
|
||||
return SemVersion.RangeRequirement {
|
||||
it in compareRange
|
||||
}
|
||||
}
|
||||
versionRule.matchEntire(trimmed)?.let { result ->
|
||||
val operator = result.groupValues[1]
|
||||
val version = SemVersion.parse(result.groupValues[7])
|
||||
return when (operator) {
|
||||
">=" -> {
|
||||
SemVersion.RangeRequirement { it >= version }
|
||||
}
|
||||
">" -> {
|
||||
SemVersion.RangeRequirement { it > version }
|
||||
}
|
||||
"<=" -> {
|
||||
SemVersion.RangeRequirement { it <= version }
|
||||
}
|
||||
"<" -> {
|
||||
SemVersion.RangeRequirement { it < version }
|
||||
}
|
||||
"=" -> {
|
||||
SemVersion.RangeRequirement { it.compareTo(version) == 0 }
|
||||
}
|
||||
else -> throw AssertionError("operator=$operator, version=$version")
|
||||
}
|
||||
}
|
||||
throw UnsupportedOperationException("Cannot parse $this")
|
||||
}
|
||||
|
||||
private fun SemVersion.RangeRequirement.withRule(rule: String): SemVersion.RangeRequirement {
|
||||
return object : SemVersion.RangeRequirement {
|
||||
override fun check(version: SemVersion): Boolean {
|
||||
return this@withRule.check(version)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return rule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseRangeRequirement(requirement: String): SemVersion.RangeRequirement {
|
||||
if (requirement.isBlank()) {
|
||||
throw IllegalArgumentException("Invalid requirement: Empty requirement rule.")
|
||||
}
|
||||
return requirement.split("||").map {
|
||||
it.parseRule().withRule(it)
|
||||
}.let { checks ->
|
||||
if (checks.size == 1) return checks[0]
|
||||
SemVersion.RangeRequirement {
|
||||
checks.forEach { rule ->
|
||||
if (rule.check(it)) return@RangeRequirement true
|
||||
}
|
||||
return@RangeRequirement false
|
||||
}.withRule(requirement)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun SemVersion.compareInternal(other: SemVersion): Int {
|
||||
// ignored metadata in comparing
|
||||
|
||||
// If $this equals $other (without metadata),
|
||||
// return same.
|
||||
if (other.mainVersion.contentEquals(mainVersion) && identifier == other.identifier) {
|
||||
return 0
|
||||
}
|
||||
fun IntArray.getSafe(index: Int) = getOrElse(index) { 0 }
|
||||
|
||||
// Compare main-version
|
||||
for (index in 0 until (max(mainVersion.size, other.mainVersion.size))) {
|
||||
val result = mainVersion.getSafe(index).compareTo(other.mainVersion.getSafe(index))
|
||||
if (result != 0) return result
|
||||
}
|
||||
// If main-versions are same.
|
||||
var identifier0 = identifier
|
||||
var identifier1 = other.identifier
|
||||
// If anyone doesn't have the identifier...
|
||||
if (identifier0 == null || identifier1 == null) {
|
||||
return when (identifier0) {
|
||||
identifier1 -> { // null == null
|
||||
// Nobody has identifier
|
||||
0
|
||||
}
|
||||
null -> {
|
||||
// $other has identifier, but $this don't have identifier
|
||||
// E.g:
|
||||
// this = 1.0.0
|
||||
// other = 1.0.0-dev
|
||||
1
|
||||
}
|
||||
// It is the opposite of the above.
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
fun String.getSafe(index: Int) = getOrElse(index) { ' ' }
|
||||
|
||||
// ignored same prefix
|
||||
fun getSameSize(s1: String, s2: String): Int {
|
||||
val size = min(s1.length, s2.length)
|
||||
// 1.0-RC19 -> 19
|
||||
// 1.0-RC107 -> 107
|
||||
var realSameSize = 0
|
||||
for (index in 0 until size) {
|
||||
if (s1[index] != s2[index]) {
|
||||
return realSameSize
|
||||
} else {
|
||||
if (!s1[index].isDigit()) {
|
||||
realSameSize = index + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return realSameSize
|
||||
}
|
||||
|
||||
// We ignore the same parts. Because we only care about the differences.
|
||||
// E.g:
|
||||
// 1.0-RC1 -> 1
|
||||
// 1.0-RC2 -> 2
|
||||
val ignoredSize = getSameSize(identifier0, identifier1)
|
||||
identifier0 = identifier0.substring(ignoredSize)
|
||||
identifier1 = identifier1.substring(ignoredSize)
|
||||
// Multi-chunk comparing
|
||||
val chunks0 = identifier0.split('-', '.', '_')
|
||||
val chunks1 = identifier1.split('-', '.', '_')
|
||||
chunkLoop@ for (index in 0 until (max(chunks0.size, chunks1.size))) {
|
||||
val value0 = chunks0.getOrNull(index)
|
||||
val value1 = chunks1.getOrNull(index)
|
||||
// Any chunk is null
|
||||
if (value0 == null || value1 == null) {
|
||||
// value0 == null && value1 == null is impossible
|
||||
return if (value0 == null) {
|
||||
// E.g:
|
||||
// value0 = 1.0-RC-dev
|
||||
// value1 = 1.0-RC-dev-1
|
||||
-1
|
||||
} else {
|
||||
// E.g:
|
||||
// value0 = 1.0-RC-dev-1
|
||||
// value1 = 1.0-RC-dev
|
||||
1
|
||||
}
|
||||
}
|
||||
try {
|
||||
val result = value0.toInt().compareTo(value1.toInt())
|
||||
if (result != 0) {
|
||||
return result
|
||||
}
|
||||
continue@chunkLoop
|
||||
} catch (ignored: NumberFormatException) {
|
||||
}
|
||||
// compare chars
|
||||
for (index0 in 0 until (max(value0.length, value1.length))) {
|
||||
val result = value0.getSafe(index0).compareTo(value1.getSafe(index0))
|
||||
if (result != 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.util
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.console.internal.util.SemVersionInternal
|
||||
import net.mamoe.mirai.console.util.SemVersion.Companion.equals
|
||||
|
||||
/**
|
||||
* 语义化版本支持
|
||||
*
|
||||
* 在阅读此文件前, 请先阅读 https://semver.org/lang/zh-CN/
|
||||
* 该文档说明了语义化版本是什么, 此文件不再过多描述
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* 这是一个例子 `1.0.0-M4+c25733b8`
|
||||
*
|
||||
* 将会解析出三个内容, mainVersion(核心版本号), identifier(先行版本号) 和 metadata(元数据).
|
||||
*
|
||||
* 对这个例子进行解析会得到
|
||||
* ```
|
||||
* SemVersion(
|
||||
* mainVersion = IntArray [1, 0, 0],
|
||||
* identifier = "M4"
|
||||
* metadata = "c25733b8"
|
||||
* )
|
||||
* ```
|
||||
* 其中 identifier 和 metadata 都是可选的, 该实现对于 mainVersion 的最大长度不作出限制,
|
||||
* 也建议 mainVersion 的长度不要过长或过短
|
||||
* 但是必须至少拥有两位及以上的版本描述符, (即必须拥有主版本号和次版本号).
|
||||
*
|
||||
* 比如 `1-M4` 是不合法的, 但是 `1.0-M4` 是合法的
|
||||
*
|
||||
*/
|
||||
@Serializable
|
||||
public data class SemVersion internal constructor(
|
||||
/** 核心版本号, 至少包含一个主版本号和一个次版本号 */
|
||||
public val mainVersion: IntArray,
|
||||
/** 先行版本号识别符 */
|
||||
public val identifier: String? = null,
|
||||
/** 版本号元数据, 不参与版本号对比([compareTo]), 但是参与版本号严格对比([equals]) */
|
||||
public val metadata: String? = null
|
||||
) : Comparable<SemVersion> {
|
||||
/**
|
||||
* 一条依赖规则
|
||||
* @see [parseRangeRequirement]
|
||||
*/
|
||||
public fun interface RangeRequirement {
|
||||
/** 在 [version] 满足此要求时返回 true */
|
||||
public fun check(version: SemVersion): Boolean
|
||||
}
|
||||
|
||||
public companion object {
|
||||
/** 解析核心版本号, eg: `1.0.0` -> IntArray[1, 0, 0] */
|
||||
@JvmStatic
|
||||
private fun String.parseMainVersion(): IntArray =
|
||||
split('.').map { it.toInt() }.toIntArray()
|
||||
|
||||
/**
|
||||
* 解析一个版本号, 将会返回一个 [SemVersion],
|
||||
* 如果发生解析错误将会抛出一个 [IllegalArgumentException] 或者 [NumberFormatException]
|
||||
*
|
||||
* 对于版本号的组成, 我们有以下规定:
|
||||
* - 必须包含主版本号和次版本号
|
||||
* - 存在 先行版本号 的时候 先行版本号 不能为空
|
||||
* - 存在 元数据 的时候 元数据 不能为空
|
||||
*
|
||||
* 注意情况:
|
||||
* - 第一个 `+` 之后的所有内容全部识别为元数据
|
||||
* - `1.0+METADATA-M4`, metadata="METADATA-M4"
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, NumberFormatException::class)
|
||||
@JvmStatic
|
||||
public fun parse(version: String): SemVersion {
|
||||
var mainVersionEnd: Int = 0
|
||||
kotlin.run {
|
||||
val iterator = version.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if (next == '-' || next == '+') {
|
||||
break
|
||||
}
|
||||
mainVersionEnd++
|
||||
}
|
||||
}
|
||||
var identifier: String? = null
|
||||
var metadata: String? = null
|
||||
if (mainVersionEnd != version.length) {
|
||||
when (version[mainVersionEnd]) {
|
||||
'-' -> {
|
||||
val metadataSplitter = version.indexOf('+', startIndex = mainVersionEnd)
|
||||
if (metadataSplitter == -1) {
|
||||
identifier = version.substring(mainVersionEnd + 1)
|
||||
} else {
|
||||
identifier = version.substring(mainVersionEnd + 1, metadataSplitter)
|
||||
metadata = version.substring(metadataSplitter + 1)
|
||||
}
|
||||
}
|
||||
'+' -> {
|
||||
metadata = version.substring(mainVersionEnd + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return SemVersion(
|
||||
mainVersion = version.substring(0, mainVersionEnd).also { mainVersion ->
|
||||
if (mainVersion.indexOf('.') == -1) {
|
||||
throw IllegalArgumentException("$mainVersion must has more than one label")
|
||||
}
|
||||
if (mainVersion.last() == '.') {
|
||||
throw IllegalArgumentException("Version string cannot end-with `.`")
|
||||
}
|
||||
}.parseMainVersion(),
|
||||
identifier = identifier?.also {
|
||||
if (it.isBlank()) {
|
||||
throw IllegalArgumentException("The identifier cannot be blank.")
|
||||
}
|
||||
},
|
||||
metadata = metadata?.also {
|
||||
if (it.isBlank()) {
|
||||
throw IllegalArgumentException("The metadata cannot be blank.")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析一条依赖需求描述, 在无法解析的时候抛出 [IllegalArgumentException]
|
||||
*
|
||||
* 对于一条规则, 有以下方式可选
|
||||
*
|
||||
* - `1.0.0-M4` 要求 1.0.0-M4 版本, 且只能是 1.0.0-M4 版本
|
||||
* - `1.x` 要求 1.x 版本
|
||||
* - `1.0.0 - 1.2.0` 要求 1.0.0 到 1.2.0 的任意版本, 注意 `-` 两边必须要有空格
|
||||
* - `[1.0.0, 1.2.0]` 与 `1.0.0 - 1.2.0` 一致
|
||||
* - `> 1.0.0-RC` 要求 1.0.0-RC 之后的版本, 不能是 1.0.0-RC
|
||||
* - `>= 1.0.0-RC` 要求 1.0.0-RC 或之后的版本, 可以是 1.0.0-RC
|
||||
* - `< 1.0.0-RC` 要求 1.0.0-RC 之前的版本, 不能是 1.0.0-RC
|
||||
* - `<= 1.0.0-RC` 要求 1.0.0-RC 或之前的版本, 可以是 1.0.0-RC
|
||||
*
|
||||
* 对于多个规则, 也允许使用 `||` 拼接在一起.
|
||||
* 例如:
|
||||
* - `1.x || 2.x || 3.0`
|
||||
* - `<= 0.5.3 || >= 1.0.0`
|
||||
*
|
||||
* 特别注意:
|
||||
* - 依赖规则版本号不需要携带版本号元数据, 元数据不参与依赖需求的检查
|
||||
* - 如果目标版本号携带有先行版本号, 请不要忘记先行版本号
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
@JvmStatic
|
||||
public fun parseRangeRequirement(requirement: String): RangeRequirement {
|
||||
return SemVersionInternal.parseRangeRequirement(requirement)
|
||||
}
|
||||
|
||||
/** @see [RangeRequirement.check] */
|
||||
@JvmStatic
|
||||
public fun RangeRequirement.check(version: String): Boolean = check(parse(version))
|
||||
|
||||
/**
|
||||
* 当满足 [requirement] 时返回 true, 否则返回 false
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun SemVersion.satisfies(requirement: RangeRequirement): Boolean = requirement.check(this)
|
||||
|
||||
/** for Kotlin only */
|
||||
@JvmStatic
|
||||
@JvmSynthetic
|
||||
public operator fun RangeRequirement.contains(version: SemVersion): Boolean = check(version)
|
||||
|
||||
/** for Kotlin only */
|
||||
@JvmStatic
|
||||
@JvmSynthetic
|
||||
public operator fun RangeRequirement.contains(version: String): Boolean = check(version)
|
||||
}
|
||||
|
||||
@Transient
|
||||
private var toString: String? = null // For cache.
|
||||
override fun toString(): String {
|
||||
return toString ?: kotlin.run {
|
||||
buildString {
|
||||
mainVersion.joinTo(this, ".")
|
||||
identifier?.let { identifier ->
|
||||
append('-')
|
||||
append(identifier)
|
||||
}
|
||||
metadata?.let { metadata ->
|
||||
append('+')
|
||||
append(metadata)
|
||||
}
|
||||
}.also { toString = it }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 [SemVersion] 转为 Kotlin data class 风格的 [String]
|
||||
*/
|
||||
public fun toStructuredString(): String {
|
||||
return "SemVersion(mainVersion=${mainVersion.contentToString()}, identifier=$identifier, metadata=$metadata)"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as SemVersion
|
||||
|
||||
return compareTo(other) == 0 && other.identifier == identifier && other.metadata == metadata
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = mainVersion.contentHashCode()
|
||||
result = 31 * result + (identifier?.hashCode() ?: 0)
|
||||
result = 31 * result + (metadata?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object with the specified object for order. Returns zero if this object is equal
|
||||
* to the specified [other] object, a negative number if it's less than [other], or a positive number
|
||||
* if it's greater than [other].
|
||||
*/
|
||||
public override operator fun compareTo(other: SemVersion): Int {
|
||||
return SemVersionInternal.run { compareInternal(other) }
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.util
|
||||
|
||||
import net.mamoe.mirai.console.util.SemVersion.Companion.check
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class TestSemVersion {
|
||||
@Test
|
||||
internal fun testCompare() {
|
||||
fun String.sem(): SemVersion = SemVersion.parse(this)
|
||||
assert("1.0".sem() < "1.0.1".sem())
|
||||
assert("1.0.0".sem() == "1.0".sem())
|
||||
assert("1.1".sem() > "1.0.0.1".sem())
|
||||
assert("1.0-M4".sem() < "1.0-M5".sem())
|
||||
assert("1.0-M5-dev-7".sem() < "1.0-M5-dev-15".sem())
|
||||
assert("1.0-M5-dev-79".sem() < "1.0-M5-dev-7001".sem())
|
||||
assert("1.0-M6".sem() > "1.0-M5-dev-15".sem())
|
||||
assert("1.0-RC".sem() > "1.0-M5-dev-15".sem())
|
||||
assert("1.0-RC2".sem() > "1.0-RC".sem())
|
||||
// example on semver
|
||||
// 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
|
||||
assert("1.0.0-alpha".sem() < "1.0.0-alpha.1".sem())
|
||||
assert("1.0.0-alpha.1".sem() < "1.0.0-alpha.beta".sem())
|
||||
assert("1.0.0-alpha.beta".sem() < "1.0.0-beta".sem())
|
||||
assert("1.0.0-beta".sem() < "1.0.0-beta.2".sem())
|
||||
assert("1.0.0-beta.2".sem() < "1.0.0-beta.11".sem())
|
||||
assert("1.0.0-beta.11".sem() < "1.0.0-rc.1".sem())
|
||||
assert("1.0.0-rc.1".sem() < "1.0.0".sem())
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun testRequirement() {
|
||||
fun SemVersion.RangeRequirement.assert(version: String): SemVersion.RangeRequirement {
|
||||
assert(check(version)) { version }
|
||||
return this
|
||||
}
|
||||
|
||||
fun SemVersion.RangeRequirement.assertFalse(version: String): SemVersion.RangeRequirement {
|
||||
assert(!check(version)) { version }
|
||||
return this
|
||||
}
|
||||
SemVersion.parseRangeRequirement("1.0")
|
||||
.assert("1.0").assert("1.0.0")
|
||||
.assert("1.0.0.0")
|
||||
.assertFalse("1.1.0").assertFalse("2.0.0")
|
||||
SemVersion.parseRangeRequirement("1.x")
|
||||
.assert("1.0").assert("1.1")
|
||||
.assert("1.5").assert("1.14514")
|
||||
.assertFalse("2.33")
|
||||
SemVersion.parseRangeRequirement("2.0 || 1.2.x")
|
||||
.assert("2.0").assert("2.0.0")
|
||||
.assertFalse("2.1").assertFalse("2.0.0.1")
|
||||
.assert("1.2.5").assert("1.2.0").assertFalse("1.2")
|
||||
.assertFalse("1.0.0")
|
||||
SemVersion.parseRangeRequirement("1.0.0 - 114.514.1919.810")
|
||||
.assert("1.0.0")
|
||||
.assert("114.514").assert("114.514.1919.810")
|
||||
.assertFalse("0.0.1")
|
||||
.assertFalse("4444.4444")
|
||||
SemVersion.parseRangeRequirement("[1.0.0, 19190.0]")
|
||||
.assert("1.0.0").assertFalse("0.1.0")
|
||||
.assert("19190.0").assertFalse("19198.10")
|
||||
SemVersion.parseRangeRequirement(" >= 1.0.0")
|
||||
.assert("1.0.0")
|
||||
.assert("114.514.1919.810")
|
||||
.assertFalse("0.0.0")
|
||||
.assertFalse("0.98774587")
|
||||
SemVersion.parseRangeRequirement("> 1.0.0")
|
||||
.assertFalse("1.0.0")
|
||||
kotlin.runCatching { SemVersion.parseRangeRequirement("WPOXAXW") }
|
||||
.onSuccess { assert(false) }
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun testSemVersionParsing() {
|
||||
fun String.check() {
|
||||
val sem = SemVersion.parse(this)
|
||||
assert(this == sem.toString()) { "$this != $sem" }
|
||||
}
|
||||
|
||||
fun String.checkInvalid() {
|
||||
kotlin.runCatching { SemVersion.parse(this) }
|
||||
.onSuccess { assert(false) { "$this not a invalid sem-version" } }
|
||||
.onFailure { println("$this - $it") }
|
||||
}
|
||||
"0.0".check()
|
||||
"1.0.0".check()
|
||||
"1.2.3.4.5.6.7.8".check()
|
||||
"5555.0-A".check()
|
||||
"5555.0-A+METADATA".check()
|
||||
"5555.0+METADATA".check()
|
||||
"987.0+wwwxx-wk".check()
|
||||
"NOT.NUMBER".checkInvalid()
|
||||
"0".checkInvalid()
|
||||
"".checkInvalid()
|
||||
"1.".checkInvalid()
|
||||
"0.1-".checkInvalid()
|
||||
"1.9+".checkInvalid()
|
||||
"5.1+68-7".check()
|
||||
"5.1+68-".check()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user