summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2016-07-21 06:22:48 -0700
committerSom Snytt <som.snytt@gmail.com>2016-07-21 06:40:27 -0700
commit06f8b6244ae8e80152f25a81cc2b92afd14c62f4 (patch)
tree388d99564016fa2ccac28c6bf9f689ee897e061b
parent656162bb48fbbd703790a2c94d4563e40ddfdfc2 (diff)
downloadscala-06f8b6244ae8e80152f25a81cc2b92afd14c62f4.tar.gz
scala-06f8b6244ae8e80152f25a81cc2b92afd14c62f4.tar.bz2
scala-06f8b6244ae8e80152f25a81cc2b92afd14c62f4.zip
SI-9750 Spec check major.minor.security
Don't assume spec is just major, but allow arbitrary version number for both spec value and user value to check. Only the first three dot-separated fields are considered, after skipping optional leading value "1" in legacy format. Minimal validity checks of user arg are applied. Leading three fields, if present, must be number values, but subsequent fields are ignored. Note that a version number is not a version string, which optionally includes pre and build info, `9-ea+109`.
-rw-r--r--src/library/scala/util/Properties.scala68
-rw-r--r--test/junit/scala/util/SpecVersionTest.scala52
2 files changed, 91 insertions, 29 deletions
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index 1bdf50bac2..8722294dde 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -168,33 +168,59 @@ private[scala] trait PropertiesTrait {
/** Compares the given specification version to the specification version of the platform.
*
- * @param version a specification version number (legacy forms acceptable)
- * @return `true` iff the specification version of the current runtime
- * is equal to or higher than the version denoted by the given string.
- * @throws NumberFormatException if the given string is not a version string
+ * @param version a specification version number (legacy forms acceptable)
+ * @return `true` if the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
*
- * @example {{{
- * // In this example, the runtime's Java specification is assumed to be at version 8.
- * isJavaAtLeast("1.6") // true
- * isJavaAtLeast("1.8") // true
- * isJavaAtLeast("8") // true
- * isJavaAtLeast("9") // false
- * isJavaAtLeast("1.9") // throws
- * }}}
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 8.
+ * isJavaAtLeast("1.8") // true
+ * isJavaAtLeast("8") // true
+ * isJavaAtLeast("9") // false
+ * isJavaAtLeast("9.1") // false
+ * isJavaAtLeast("1.9") // throws
+ * }}}
*/
def isJavaAtLeast(version: String): Boolean = {
- def versionOf(s: String): Int = s.indexOf('.') match {
- case 1 if s.charAt(0) == '1' =>
- val v = s.substring(2).toInt
- if (v < 9) v else -1
- case -1 => s.toInt
- case _ => -1
+ def versionOf(s: String, depth: Int): (Int, String) =
+ s.indexOf('.') match {
+ case 0 =>
+ (-2, s.substring(1))
+ case 1 if depth == 0 && s.charAt(0) == '1' =>
+ val r0 = s.substring(2)
+ val (v, r) = versionOf(r0, 1)
+ val n = if (v > 8 || r0.isEmpty) -2 else v // accept 1.8, not 1.9 or 1.
+ (n, r)
+ case -1 =>
+ val n = if (!s.isEmpty) s.toInt else if (depth == 0) -2 else 0
+ (n, "")
+ case i =>
+ val r = s.substring(i + 1)
+ val n = if (depth < 2 && r.isEmpty) -2 else s.substring(0, i).toInt
+ (n, r)
+ }
+ def compareVersions(s: String, v: String, depth: Int): Int = {
+ if (depth >= 3) 0
+ else {
+ val (sn, srest) = versionOf(s, depth)
+ val (vn, vrest) = versionOf(v, depth)
+ if (vn < 0) -2
+ else if (sn < vn) -1
+ else if (sn > vn) 1
+ else compareVersions(srest, vrest, depth + 1)
+ }
+ }
+ compareVersions(javaSpecVersion, version, 0) match {
+ case -2 => throw new NumberFormatException(s"Not a version: $version")
+ case i => i >= 0
}
- val v = versionOf(version)
- if (v < 0) throw new NumberFormatException(s"Not a version: $version")
- versionOf(javaSpecVersion) >= v
}
+ /** Tests whether the major version of the platform specification is at least the given value.
+ *
+ * @param version a major version number
+ */
def isJavaAtLeast(version: Int): Boolean = isJavaAtLeast(version.toString)
// provide a main method so version info can be obtained by running this
diff --git a/test/junit/scala/util/SpecVersionTest.scala b/test/junit/scala/util/SpecVersionTest.scala
index 9232c4721b..4639389dd9 100644
--- a/test/junit/scala/util/SpecVersionTest.scala
+++ b/test/junit/scala/util/SpecVersionTest.scala
@@ -34,6 +34,8 @@ class SpecVersionTest {
assert(sut9 isJavaAtLeast "8")
assert(sut9 isJavaAtLeast "9")
assert(sut9.isJavaAtLeast(9))
+ assertFalse(sut9.isJavaAtLeast(10))
+ assertFalse(sut9.isJavaAtLeast("10"))
}
// SI-7265
@@ -53,15 +55,49 @@ class SpecVersionTest {
}
@Test def variousBadVersionStrings(): Unit = {
- val sut7 = new TestProperties("1.7")
- val sut9 = new TestProperties("9")
- assertThrows[NumberFormatException](sut7.isJavaAtLeast("1.9"), _ == "Not a version: 1.9")
- assertThrows[NumberFormatException] { sut9 isJavaAtLeast "1.9" }
- assertThrows[NumberFormatException] { sut7 isJavaAtLeast "9.1" }
- assertThrows[NumberFormatException] { sut9 isJavaAtLeast "9.1" }
+ val sut = new TestProperties("9")
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("1.9"), _ == "Not a version: 1.9")
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("1."))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("1.8."))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("1.a"))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast(""))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("."))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast(".."))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast(".5"))
+ assertThrows[NumberFormatException](sut.isJavaAtLeast("9-ea")) //version number, not version string
+ }
- val badvs = List("1.1.8", "1.", "1.a", "", ".", ".5", "1.7.1")
+ @Test def `spec has minor or more`(): Unit = {
+ val sut = new TestProperties("9.2.5")
+ assert(sut.isJavaAtLeast(9))
+ assert(sut.isJavaAtLeast("9"))
+ assert(sut.isJavaAtLeast("9.0.1"))
+ assert(sut.isJavaAtLeast("9.2.1"))
+ assert(sut.isJavaAtLeast("8.3.1"))
+ assert(sut.isJavaAtLeast("8.3.1.1.1"))
+ assertFalse(sut.isJavaAtLeast("9.3.1"))
+ assertFalse(sut.isJavaAtLeast("10.3.1"))
+ }
+
+ @Test def `compares only major minor security`(): Unit = {
+ val sut = new TestProperties("9.2.5.1.2.3")
+ assert(sut.isJavaAtLeast(9))
+ assert(sut.isJavaAtLeast("9"))
+ assert(sut.isJavaAtLeast("9.0.1"))
+ assert(sut.isJavaAtLeast("9.2.5.9.9.9"))
+ assertFalse(sut.isJavaAtLeast("9.2.6"))
+ }
- for (v <- badvs) assertThrows[NumberFormatException](sut7.isJavaAtLeast(v))
+ @Test def `futurely proofed`(): Unit = {
+ val sut = new TestProperties("10.2.5")
+ assert(sut.isJavaAtLeast(9))
+ assert(sut.isJavaAtLeast(10))
+ assert(sut.isJavaAtLeast("9"))
+ assert(sut.isJavaAtLeast("9.0.1"))
+ assert(sut.isJavaAtLeast("9.2.1"))
+ assert(sut.isJavaAtLeast("8.3.1"))
+ assert(sut.isJavaAtLeast("8.3.1.1.1"))
+ assert(sut.isJavaAtLeast("9.3.1"))
+ assertFalse(sut.isJavaAtLeast("10.3.1"))
}
}