Merge pull request #221 from dwijnand/cleanup/VersionNumberSpec

Cleanup VersionNumberSpec
This commit is contained in:
Dale Wijnand 2018-03-20 09:36:36 +00:00 committed by GitHub
commit c6b2b626c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 174 additions and 126 deletions

View File

@ -1,128 +1,155 @@
package sbt.librarymanagement
import sbt.internal.librarymanagement.UnitSpec
import org.scalatest.{ FreeSpec, Inside, Matchers }
// This is a specification to check the version number parsing.
class VersionNumberSpec extends UnitSpec {
"1" should "be parsed" in beParsedAs("1", Seq(1), Seq(), Seq())
it should "breakdown" in breakDownTo("1", Some(1))
it should "cascade" in generateCorrectCascadingNumbers("1", Seq("1"))
// This is a specification to check VersionNumber and VersionNumberCompatibility.
class VersionNumberSpec extends FreeSpec with Matchers with Inside {
import VersionNumber.{ SemVer, SecondSegment }
"1.0" should "be parsed" in beParsedAs("1.0", Seq(1, 0), Seq(), Seq())
it should "breakdown" in breakDownTo("1.0", Some(1), Some(0))
it should "cascade" in generateCorrectCascadingNumbers("1.0", Seq("1.0"))
"1.0.0" should "be parsed" in beParsedAs("1.0.0", Seq(1, 0, 0), Seq(), Seq())
it should "breakdown" in breakDownTo("1.0.0", Some(1), Some(0), Some(0))
it should "cascade" in generateCorrectCascadingNumbers("1.0.0", Seq("1.0.0", "1.0"))
it should "be SemVer compat with 1.0.1" in beSemVerCompatWith("1.0.0", "1.0.1")
it should "be SemVer compat with 1.1.1" in beSemVerCompatWith("1.0.0", "1.1.1")
it should "not be SemVer compat with 2.0.0" in notBeSemVerCompatWith("1.0.0", "2.0.0")
it should "not be SemVer compat with 1.0.0-M1" in notBeSemVerCompatWith("1.0.0", "1.0.0-M1")
it should "be SecSeg compat with 1.0.1" in beSecSegCompatWith("1.0.0", "1.0.1")
it should "not be SecSeg compat with 1.1.1" in notBeSecSegCompatWith("1.0.0", "1.1.1")
it should "not be SecSeg compat with 2.0.0" in notBeSecSegCompatWith("1.0.0", "2.0.0")
it should "not be SecSeg compat with 1.0.0-M1" in notBeSecSegCompatWith("1.0.0", "1.0.0-M1")
"1.0.0.0" should "be parsed" in beParsedAs("1.0.0.0", Seq(1, 0, 0, 0), Seq(), Seq())
it should "breakdown" in breakDownTo("1.0.0.0", Some(1), Some(0), Some(0), Some(0))
it should "cascade" in generateCorrectCascadingNumbers("1.0.0.0", Seq("1.0.0.0", "1.0.0", "1.0"))
"0.12.0" should "be parsed" in beParsedAs("0.12.0", Seq(0, 12, 0), Seq(), Seq())
it should "breakdown" in breakDownTo("0.12.0", Some(0), Some(12), Some(0))
it should "cascade" in generateCorrectCascadingNumbers("0.12.0", Seq("0.12.0", "0.12"))
it should "not be SemVer compat with 0.12.0-RC1" in notBeSemVerCompatWith("0.12.0", "0.12.0-RC1")
it should "not be SemVer compat with 0.12.1" in notBeSemVerCompatWith("0.12.0", "0.12.1")
it should "not be SemVer compat with 0.12.1-M1" in notBeSemVerCompatWith("0.12.0", "0.12.1-M1")
it should "not be SecSeg compat with 0.12.0-RC1" in notBeSecSegCompatWith("0.12.0", "0.12.0-RC1")
it should "be SecSeg compat with 0.12.1" in beSecSegCompatWith("0.12.0", "0.12.1")
it should "be SecSeg compat with 0.12.1-M1" in beSecSegCompatWith("0.12.0", "0.12.1-M1")
"0.1.0-SNAPSHOT" should "be parsed" in beParsedAs("0.1.0-SNAPSHOT",
Seq(0, 1, 0),
Seq("SNAPSHOT"),
Seq())
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-SNAPSHOT",
Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1"))
it should "be SemVer compat with 0.1.0-SNAPSHOT" in beSemVerCompatWith("0.1.0-SNAPSHOT",
"0.1.0-SNAPSHOT")
it should "not be SemVer compat with 0.1.0" in notBeSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0")
it should "be SemVer compat with 0.1.0-SNAPSHOT+001" in beSemVerCompatWith("0.1.0-SNAPSHOT",
"0.1.0-SNAPSHOT+001")
it should "be SecSeg compat with 0.1.0-SNAPSHOT" in beSecSegCompatWith("0.1.0-SNAPSHOT",
"0.1.0-SNAPSHOT")
it should "be not SecSeg compat with 0.1.0" in notBeSecSegCompatWith("0.1.0-SNAPSHOT", "0.1.0")
it should "be SecSeg compat with 0.1.0-SNAPSHOT+001" in beSecSegCompatWith("0.1.0-SNAPSHOT",
"0.1.0-SNAPSHOT+001")
"0.1.0-M1" should "be parsed" in beParsedAs("0.1.0-M1", Seq(0, 1, 0), Seq("M1"), Seq())
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-M1",
Seq("0.1.0-M1", "0.1.0", "0.1"))
"0.1.0-RC1" should "be parsed" in beParsedAs("0.1.0-RC1", Seq(0, 1, 0), Seq("RC1"), Seq())
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-RC1",
Seq("0.1.0-RC1", "0.1.0", "0.1"))
"0.1.0-MSERVER-1" should "be parsed" in beParsedAs("0.1.0-MSERVER-1",
Seq(0, 1, 0),
Seq("MSERVER", "1"),
Seq())
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-MSERVER-1",
Seq("0.1.0-MSERVER-1", "0.1.0", "0.1"))
"2.10.4-20140115-000117-b3a-sources" should "be parsed" in {
beParsedAs("2.10.4-20140115-000117-b3a-sources",
Seq(2, 10, 4),
Seq("20140115", "000117", "b3a", "sources"),
Seq())
version("1") { v =>
assertParsesTo(v, Seq(1), Seq(), Seq())
assertBreaksDownTo(v, Some(1))
assertCascadesTo(v, Seq("1"))
}
it should "cascade" in generateCorrectCascadingNumbers(
"2.10.4-20140115-000117-b3a-sources",
Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10"))
it should "be SemVer compat with 2.0.0" in beSemVerCompatWith(
"2.10.4-20140115-000117-b3a-sources",
"2.0.0")
it should "be not SecSeg compat with 2.0.0" in notBeSecSegCompatWith(
"2.10.4-20140115-000117-b3a-sources",
"2.0.0")
"20140115000117-b3a-sources" should "be parsed" in {
beParsedAs("20140115000117-b3a-sources", Seq(20140115000117L), Seq("b3a", "sources"), Seq())
version("1.0") { v =>
assertParsesTo(v, Seq(1, 0), Seq(), Seq())
assertBreaksDownTo(v, Some(1), Some(0))
assertCascadesTo(v, Seq("1.0"))
}
it should "cascade" in generateCorrectCascadingNumbers("20140115000117-b3a-sources",
Seq("20140115000117-b3a-sources"))
"1.0.0-alpha+001+002" should "be parsed" in {
beParsedAs("1.0.0-alpha+001+002", Seq(1, 0, 0), Seq("alpha"), Seq("+001", "+002"))
version("1.0.0") { v =>
assertParsesTo(v, Seq(1, 0, 0), Seq(), Seq())
assertBreaksDownTo(v, Some(1), Some(0), Some(0))
assertCascadesTo(v, Seq("1.0.0", "1.0"))
assertIsCompatibleWith(v, "1.0.1", SemVer)
assertIsCompatibleWith(v, "1.1.1", SemVer)
assertIsNotCompatibleWith(v, "2.0.0", SemVer)
assertIsNotCompatibleWith(v, "1.0.0-M1", SemVer)
assertIsCompatibleWith(v, "1.0.1", SecondSegment)
assertIsNotCompatibleWith(v, "1.1.1", SecondSegment)
assertIsNotCompatibleWith(v, "2.0.0", SecondSegment)
assertIsNotCompatibleWith(v, "1.0.0-M1", SecondSegment)
}
it should "cascade" in generateCorrectCascadingNumbers(
"1.0.0-alpha+001+002",
Seq("1.0.0-alpha+001+002", "1.0.0", "1.0")
)
"non.space.!?string" should "be parsed" in {
beParsedAs("non.space.!?string", Seq(), Seq(), Seq("non.space.!?string"))
version("1.0.0.0") { v =>
assertParsesTo(v, Seq(1, 0, 0, 0), Seq(), Seq())
assertBreaksDownTo(v, Some(1), Some(0), Some(0), Some(0))
assertCascadesTo(v, Seq("1.0.0.0", "1.0.0", "1.0"))
}
it should "cascade" in generateCorrectCascadingNumbers("non.space.!?string",
Seq("non.space.!?string"))
"space !?string" should "be parsed as an error" in beParsedAsError("space !?string")
"blank string" should "be parsed as an error" in beParsedAsError("")
version("0.12.0") { v =>
assertParsesTo(v, Seq(0, 12, 0), Seq(), Seq())
assertBreaksDownTo(v, Some(0), Some(12), Some(0))
assertCascadesTo(v, Seq("0.12.0", "0.12"))
def beParsedAs(s: String, ns: Seq[Long], ts: Seq[String], es: Seq[String]) =
s match {
case VersionNumber(ns1, ts1, es1) if (ns1 == ns && ts1 == ts && es1 == es) =>
(VersionNumber(ns, ts, es).toString shouldBe s)
(VersionNumber(ns, ts, es) shouldBe VersionNumber(ns, ts, es))
case VersionNumber(ns1, ts1, es1) =>
sys.error(s"$ns1, $ts1, $es1")
assertIsNotCompatibleWith(v, "0.12.0-RC1", SemVer)
assertIsNotCompatibleWith(v, "0.12.1", SemVer)
assertIsNotCompatibleWith(v, "0.12.1-M1", SemVer)
assertIsNotCompatibleWith(v, "0.12.0-RC1", SecondSegment)
assertIsCompatibleWith(v, "0.12.1", SecondSegment)
assertIsCompatibleWith(v, "0.12.1-M1", SecondSegment)
}
version("0.1.0-SNAPSHOT") { v =>
assertParsesTo(v, Seq(0, 1, 0), Seq("SNAPSHOT"), Seq())
assertCascadesTo(v, Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1"))
assertIsCompatibleWith(v, "0.1.0-SNAPSHOT", SemVer)
assertIsNotCompatibleWith(v, "0.1.0", SemVer)
assertIsCompatibleWith(v, "0.1.0-SNAPSHOT+001", SemVer)
assertIsCompatibleWith(v, "0.1.0-SNAPSHOT", SecondSegment)
assertIsNotCompatibleWith(v, "0.1.0", SecondSegment)
assertIsCompatibleWith(v, "0.1.0-SNAPSHOT+001", SecondSegment)
}
version("0.1.0-M1") { v =>
assertParsesTo(v, Seq(0, 1, 0), Seq("M1"), Seq())
assertCascadesTo(v, Seq("0.1.0-M1", "0.1.0", "0.1"))
}
version("0.1.0-RC1") { v =>
assertParsesTo(v, Seq(0, 1, 0), Seq("RC1"), Seq())
assertCascadesTo(v, Seq("0.1.0-RC1", "0.1.0", "0.1"))
}
version("0.1.0-MSERVER-1") { v =>
assertParsesTo(v, Seq(0, 1, 0), Seq("MSERVER", "1"), Seq())
assertCascadesTo(v, Seq("0.1.0-MSERVER-1", "0.1.0", "0.1"))
}
version("2.10.4-20140115-000117-b3a-sources") { v =>
assertParsesTo(v, Seq(2, 10, 4), Seq("20140115", "000117", "b3a", "sources"), Seq())
assertCascadesTo(v, Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10"))
assertIsCompatibleWith(v, "2.0.0", SemVer)
assertIsNotCompatibleWith(v, "2.0.0", SecondSegment)
}
version("20140115000117-b3a-sources") { v =>
assertParsesTo(v, Seq(20140115000117L), Seq("b3a", "sources"), Seq())
assertCascadesTo(v, Seq("20140115000117-b3a-sources"))
}
version("1.0.0-alpha+001+002") { v =>
assertParsesTo(v, Seq(1, 0, 0), Seq("alpha"), Seq("+001", "+002"))
assertCascadesTo(v, Seq("1.0.0-alpha+001+002", "1.0.0", "1.0"))
}
version("non.space.!?string") { v =>
assertParsesTo(v, Seq(), Seq(), Seq("non.space.!?string"))
assertCascadesTo(v, Seq("non.space.!?string"))
}
version("space !?string") { v =>
assertParsesToError(v)
}
version("") { v =>
assertParsesToError(v)
}
////
private[this] final class VersionString(val value: String)
private[this] def version(s: String)(f: VersionString => Unit) =
s"""Version "$s"""" - {
f(new VersionString(s))
}
def breakDownTo(s: String,
major: Option[Long],
minor: Option[Long] = None,
patch: Option[Long] = None,
buildNumber: Option[Long] = None) =
s match {
private[this] def assertParsesTo(
v: VersionString,
ns: Seq[Long],
ts: Seq[String],
es: Seq[String]
): Unit =
s"should parse to ($ns, $ts, $es)" in inside(v.value) {
case VersionNumber(ns1, ts1, es1) =>
(ns1 shouldBe ns)
(ts1 shouldBe ts)
(es1 shouldBe es)
(VersionNumber(ns, ts, es).toString shouldBe v.value)
(VersionNumber(ns, ts, es) shouldBe VersionNumber(ns, ts, es))
}
private[this] def assertParsesToError(v: VersionString): Unit =
"should parse as an error" in {
v.value should not matchPattern {
case s: String if VersionNumber.unapply(s).isDefined => // because of unapply overloading
}
}
private[this] def assertBreaksDownTo(
v: VersionString,
major: Option[Long],
minor: Option[Long] = None,
patch: Option[Long] = None,
buildNumber: Option[Long] = None
): Unit =
s"should breakdown to ($major, $minor, $patch, $buildNumber)" in inside(v.value) {
case VersionNumber(ns, ts, es) =>
val v = VersionNumber(ns, ts, es)
(v._1 shouldBe major)
@ -130,21 +157,42 @@ class VersionNumberSpec extends UnitSpec {
(v._3 shouldBe patch)
(v._4 shouldBe buildNumber)
}
def beParsedAsError(s: String): Unit =
s match {
case VersionNumber(_, _, _) => sys.error(s)
case _ => ()
private[this] def assertCascadesTo(v: VersionString, ns: Seq[String]): Unit = {
s"should cascade to $ns" in {
val versionNumbers = ns.toVector map VersionNumber.apply
VersionNumber(v.value).cascadingVersions shouldBe versionNumbers
}
}
private[this] def assertIsCompatibleWith(
v1: VersionString,
v2: String,
vnc: VersionNumberCompatibility
): Unit =
checkCompat(true, vnc, v1, v2)
private[this] def assertIsNotCompatibleWith(
v1: VersionString,
v2: String,
vnc: VersionNumberCompatibility
): Unit =
checkCompat(false, vnc, v1, v2)
private[this] def checkCompat(
expectOutcome: Boolean,
vnc: VersionNumberCompatibility,
v1: VersionString,
v2: String
) = {
val prefix = if (expectOutcome) "should" else "should NOT"
val compatibilityStrategy = vnc match {
case SemVer => "SemVer"
case SecondSegment => "SecondSegment"
case _ => val s = vnc.name; if (s contains " ") s""""$s"""" else s
}
s"$prefix be $compatibilityStrategy compatible with $v2" in {
vnc.isCompatible(VersionNumber(v1.value), VersionNumber(v2)) shouldBe expectOutcome
}
def beSemVerCompatWith(v1: String, v2: String) =
VersionNumber.SemVer.isCompatible(VersionNumber(v1), VersionNumber(v2)) shouldBe true
def notBeSemVerCompatWith(v1: String, v2: String) =
VersionNumber.SemVer.isCompatible(VersionNumber(v1), VersionNumber(v2)) shouldBe false
def beSecSegCompatWith(v1: String, v2: String) =
VersionNumber.SecondSegment.isCompatible(VersionNumber(v1), VersionNumber(v2)) shouldBe true
def notBeSecSegCompatWith(v1: String, v2: String) =
VersionNumber.SecondSegment.isCompatible(VersionNumber(v1), VersionNumber(v2)) shouldBe false
def generateCorrectCascadingNumbers(s: String, ns: Seq[String]) = {
val versionNumbers = ns.toVector map VersionNumber.apply
VersionNumber(s).cascadingVersions shouldBe versionNumbers
}
}