Provide string-to-number conversions in JS and common stdlib.
Relates to #KT-8286 #KT-4497 Fixed
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.text
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toByte(): Byte = toByteOrNull() ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toByte(radix: Int): Byte = toByteOrNull(radix) ?: numberFormatError(this)
|
||||
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toShort(): Short = toShortOrNull() ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toShort(radix: Int): Short = toShortOrNull(radix) ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toInt(): Int = toIntOrNull() ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toInt(radix: Int): Int = toIntOrNull(radix) ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toLong(): Long = toLongOrNull() ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toLong(radix: Int): Long = toLongOrNull(radix) ?: numberFormatError(this)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toDouble(): Double = (+(this.asDynamic())).unsafeCast<Double>().also {
|
||||
if (it.isNaN() && !this.isNaN())
|
||||
numberFormatError(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
public inline fun String.toFloat(): Float = toDouble().unsafeCast<Float>()
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
public fun String.toDoubleOrNull(): Double? = (+(this.asDynamic())).unsafeCast<Double>().takeIf {
|
||||
!(it.isNaN() && !this.isNaN())
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
public inline fun String.toFloatOrNull(): Float? = toDoubleOrNull().unsafeCast<Float?>()
|
||||
|
||||
|
||||
private fun String.isNaN(): Boolean = when(this.toLowerCase()) {
|
||||
"nan", "+nan", "-nan" -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given [radix] is valid radix for string to number and number to string conversion.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun checkRadix(radix: Int): Int {
|
||||
if(radix !in 2..36) {
|
||||
throw IllegalArgumentException("radix $radix was not in valid range 2..36")
|
||||
}
|
||||
return radix
|
||||
}
|
||||
|
||||
internal fun digitOf(char: Char, radix: Int): Int = when {
|
||||
char >= '0' && char <= '9' -> char - '0'
|
||||
char >= 'A' && char <= 'Z' -> char - 'A' + 10
|
||||
char >= 'a' && char <= 'z' -> char - 'a' + 10
|
||||
else -> -1
|
||||
}.let { if (it >= radix) -1 else it }
|
||||
|
||||
private fun numberFormatError(input: String): Nothing = throw NumberFormatException("Invalid number format: '$input'")
|
||||
+4
-1
@@ -19,4 +19,7 @@ package kotlin.test
|
||||
public fun assertTypeEquals(expected: Any?, actual: Any?) {
|
||||
//TODO: find analogue
|
||||
//assertEquals(expected?.javaClass, actual?.javaClass)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun String.removeLeadingPlusOnJava6(): String = this
|
||||
internal fun doubleTotalOrderEquals(a: Double?, b: Double?) = a == b || (a != a && b != b)
|
||||
@@ -31,7 +31,7 @@ public class StdLibTestToJSTest extends StdLibQUnitTestSupport {
|
||||
"collections/IteratorsTest.kt",
|
||||
"collections/CollectionBehaviors.kt",
|
||||
"collections/ComparisonDSL.kt",
|
||||
"../../../js/js.libraries/test/core/assertTypeEquals.kt",
|
||||
"../../../js/js.libraries/test/core/testUtils.kt",
|
||||
"text/StringTest.kt",
|
||||
"OrderingTest.kt",
|
||||
"collections/SequenceTest.kt",
|
||||
|
||||
@@ -121,3 +121,83 @@ internal inline header fun String.nativeLastIndexOf(ch: Char, fromIndex: Int): I
|
||||
|
||||
header fun CharSequence.isBlank(): Boolean
|
||||
header fun CharSequence.regionMatches(thisOffset: Int, other: CharSequence, otherOffset: Int, length: Int, ignoreCase: Boolean): Boolean
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toByte(): Byte
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toByte(radix: Int): Byte
|
||||
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toShort(): Short
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toShort(radix: Int): Short
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toInt(): Int
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toInt(radix: Int): Int
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toLong(): Long
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toLong(radix: Int): Long
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toDouble(): Double
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toFloat(): Float
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toDoubleOrNull(): Double?
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
header fun String.toFloatOrNull(): Float?
|
||||
|
||||
|
||||
@PublishedApi
|
||||
internal header fun checkRadix(radix: Int): Int
|
||||
internal header fun digitOf(char: Char, radix: Int): Int
|
||||
@@ -1,6 +1,5 @@
|
||||
@file:kotlin.jvm.JvmMultifileClass
|
||||
@file:kotlin.jvm.JvmName("StringsKt")
|
||||
@file:kotlin.jvm.JvmVersion
|
||||
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
|
||||
package kotlin.text
|
||||
@@ -9,6 +8,7 @@ package kotlin.text
|
||||
* Returns a string representation of this [Byte] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Byte.toString(radix: Int): String = this.toInt().toString(checkRadix(radix))
|
||||
|
||||
@@ -16,6 +16,7 @@ public inline fun Byte.toString(radix: Int): String = this.toInt().toString(chec
|
||||
* Returns a string representation of this [Short] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Short.toString(radix: Int): String = this.toInt().toString(checkRadix(radix))
|
||||
|
||||
@@ -23,6 +24,7 @@ public inline fun Short.toString(radix: Int): String = this.toInt().toString(che
|
||||
* Returns a string representation of this [Int] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Int.toString(radix: Int): String = java.lang.Integer.toString(this, checkRadix(radix))
|
||||
|
||||
@@ -30,12 +32,14 @@ public inline fun Int.toString(radix: Int): String = java.lang.Integer.toString(
|
||||
* Returns a string representation of this [Long] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Long.toString(radix: Int): String = java.lang.Long.toString(this, checkRadix(radix))
|
||||
|
||||
/**
|
||||
* Returns `true` if the contents of this string is equal to the word "true", ignoring case, and `false` otherwise.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(this)
|
||||
|
||||
@@ -43,6 +47,7 @@ public inline fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(t
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toByte(): Byte = java.lang.Byte.parseByte(this)
|
||||
|
||||
@@ -51,6 +56,7 @@ public inline fun String.toByte(): Byte = java.lang.Byte.parseByte(this)
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toByte(radix: Int): Byte = java.lang.Byte.parseByte(this, checkRadix(radix))
|
||||
|
||||
@@ -59,6 +65,7 @@ public inline fun String.toByte(radix: Int): Byte = java.lang.Byte.parseByte(thi
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toShort(): Short = java.lang.Short.parseShort(this)
|
||||
|
||||
@@ -67,6 +74,7 @@ public inline fun String.toShort(): Short = java.lang.Short.parseShort(this)
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toShort(radix: Int): Short = java.lang.Short.parseShort(this, checkRadix(radix))
|
||||
|
||||
@@ -74,6 +82,7 @@ public inline fun String.toShort(radix: Int): Short = java.lang.Short.parseShort
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toInt(): Int = java.lang.Integer.parseInt(this)
|
||||
|
||||
@@ -82,6 +91,7 @@ public inline fun String.toInt(): Int = java.lang.Integer.parseInt(this)
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toInt(radix: Int): Int = java.lang.Integer.parseInt(this, checkRadix(radix))
|
||||
|
||||
@@ -89,6 +99,7 @@ public inline fun String.toInt(radix: Int): Int = java.lang.Integer.parseInt(thi
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toLong(): Long = java.lang.Long.parseLong(this)
|
||||
|
||||
@@ -97,6 +108,7 @@ public inline fun String.toLong(): Long = java.lang.Long.parseLong(this)
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(this, checkRadix(radix))
|
||||
|
||||
@@ -104,6 +116,7 @@ public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(thi
|
||||
* Parses the string as a [Float] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toFloat(): Float = java.lang.Float.parseFloat(this)
|
||||
|
||||
@@ -111,6 +124,7 @@ public inline fun String.toFloat(): Float = java.lang.Float.parseFloat(this)
|
||||
* Parses the string as a [Double] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toDouble(): Double = java.lang.Double.parseDouble(this)
|
||||
|
||||
@@ -279,6 +293,7 @@ public fun String.toLongOrNull(radix: Int): Long? {
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
public fun String.toFloatOrNull(): Float? = screenFloatValue(this, java.lang.Float::parseFloat)
|
||||
|
||||
/**
|
||||
@@ -286,11 +301,13 @@ public fun String.toFloatOrNull(): Float? = screenFloatValue(this, java.lang.Flo
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.jvm.JvmVersion
|
||||
public fun String.toDoubleOrNull(): Double? = screenFloatValue(this, java.lang.Double::parseDouble)
|
||||
|
||||
/**
|
||||
* Recommended floating point number validation RegEx from the javadoc of `java.lang.Double.valueOf(String)`
|
||||
*/
|
||||
@kotlin.jvm.JvmVersion
|
||||
private object ScreenFloatValueRegEx {
|
||||
@JvmField val value = run {
|
||||
val Digits = "(\\p{Digit}+)"
|
||||
@@ -310,6 +327,7 @@ private object ScreenFloatValueRegEx {
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
private inline fun <T> screenFloatValue(str: String, parse: (String) -> T): T? {
|
||||
return try {
|
||||
if (ScreenFloatValueRegEx.value.matches(str))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@file:kotlin.jvm.JvmVersion
|
||||
package test.text
|
||||
|
||||
import kotlin.test.*
|
||||
@@ -6,6 +5,7 @@ import org.junit.Test
|
||||
|
||||
class StringNumberConversionTest {
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun toBoolean() {
|
||||
assertEquals(true, "true".toBoolean())
|
||||
assertEquals(true, "True".toBoolean())
|
||||
@@ -125,6 +125,7 @@ class StringNumberConversionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun toFloat() {
|
||||
compareConversion(String::toFloat, String::toFloatOrNull) {
|
||||
assertProduces("77.0", 77.0f)
|
||||
@@ -135,7 +136,7 @@ class StringNumberConversionTest {
|
||||
}
|
||||
|
||||
@Test fun toDouble() {
|
||||
compareConversion(String::toDouble, String::toDoubleOrNull) {
|
||||
compareConversion(String::toDouble, String::toDoubleOrNull, ::doubleTotalOrderEquals) {
|
||||
assertProduces("-77", -77.0)
|
||||
assertProduces("77.", 77.0)
|
||||
assertProduces("77.0", 77.0)
|
||||
@@ -147,15 +148,23 @@ class StringNumberConversionTest {
|
||||
|
||||
assertProduces("-NaN", -Double.NaN)
|
||||
assertProduces("+Infinity", Double.POSITIVE_INFINITY)
|
||||
assertProduces("0x77p1", (0x77 shl 1).toDouble())
|
||||
assertProduces("0x.77P8", 0x77.toDouble())
|
||||
|
||||
assertFailsOrNull("7..7")
|
||||
assertFailsOrNull("0x77e1")
|
||||
assertFailsOrNull("007 not a number")
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun toHexDouble() {
|
||||
compareConversion(String::toDouble, String::toDoubleOrNull, ::doubleTotalOrderEquals) {
|
||||
assertProduces("0x77p1", (0x77 shl 1).toDouble())
|
||||
assertProduces("0x.77P8", 0x77.toDouble())
|
||||
|
||||
assertFailsOrNull("0x77e1")
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun byteToStringWithRadix() {
|
||||
assertEquals("7a", 0x7a.toByte().toString(16))
|
||||
assertEquals("-80", Byte.MIN_VALUE.toString(radix = 16))
|
||||
@@ -166,6 +175,7 @@ class StringNumberConversionTest {
|
||||
assertFailsWith<IllegalArgumentException>("Expected to fail with radix 1") { 1.toByte().toString(radix = 1) }
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun shortToStringWithRadix() {
|
||||
assertEquals("7FFF", 0x7FFF.toShort().toString(radix = 16).toUpperCase())
|
||||
assertEquals("-8000", (-0x8000).toShort().toString(radix = 16))
|
||||
@@ -175,6 +185,7 @@ class StringNumberConversionTest {
|
||||
assertFailsWith<IllegalArgumentException>("Expected to fail with radix 1") { 1.toShort().toString(radix = 1) }
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun intToStringWithRadix() {
|
||||
assertEquals("-ff", (-255).toString(radix = 16))
|
||||
assertEquals("1100110", 102.toString(radix = 2))
|
||||
@@ -184,6 +195,7 @@ class StringNumberConversionTest {
|
||||
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
@Test fun longToStringWithRadix() {
|
||||
assertEquals("7f11223344556677", 0x7F11223344556677.toString(radix = 16))
|
||||
assertEquals("hazelnut", 1356099454469L.toString(radix = 36))
|
||||
@@ -197,8 +209,9 @@ class StringNumberConversionTest {
|
||||
|
||||
private fun <T : Any> compareConversion(convertOrFail: (String) -> T,
|
||||
convertOrNull: (String) -> T?,
|
||||
equality: (T, T?) -> Boolean = { a, b -> a == b },
|
||||
assertions: ConversionContext<T>.() -> Unit) {
|
||||
ConversionContext(convertOrFail, convertOrNull).assertions()
|
||||
ConversionContext(convertOrFail, convertOrNull, equality).assertions()
|
||||
}
|
||||
|
||||
|
||||
@@ -210,10 +223,16 @@ private fun <T : Any> compareConversionWithRadix(convertOrFail: String.(Int) ->
|
||||
|
||||
|
||||
private class ConversionContext<T: Any>(val convertOrFail: (String) -> T,
|
||||
val convertOrNull: (String) -> T?) {
|
||||
val convertOrNull: (String) -> T?,
|
||||
val equality: (T, T?) -> Boolean) {
|
||||
|
||||
private fun assertEquals(expected: T, actual: T?, input: String, operation: String) {
|
||||
assertTrue(equality(expected, actual), "Expected $operation('$input') to produce $expected but was $actual")
|
||||
}
|
||||
|
||||
fun assertProduces(input: String, output: T) {
|
||||
assertEquals(output, convertOrFail(input.removeLeadingPlusOnJava6()))
|
||||
assertEquals(output, convertOrNull(input))
|
||||
assertEquals(output, convertOrFail(input.removeLeadingPlusOnJava6()), input, "convertOrFail")
|
||||
assertEquals(output, convertOrNull(input), input, "convertOrNull")
|
||||
}
|
||||
|
||||
fun assertFailsOrNull(input: String) {
|
||||
@@ -222,22 +241,27 @@ private class ConversionContext<T: Any>(val convertOrFail: (String) -> T,
|
||||
}
|
||||
}
|
||||
|
||||
private class ConversionWithRadixContext<T: Any>(val convertOrFail: String.(Int) -> T,
|
||||
val convertOrNull: String.(Int) -> T?) {
|
||||
private class ConversionWithRadixContext<T: Any>(val convertOrFail: (String, Int) -> T,
|
||||
val convertOrNull: (String, Int) -> T?) {
|
||||
fun assertProduces(radix: Int, input: String, output: T) {
|
||||
assertEquals(output, input.removeLeadingPlusOnJava6().convertOrFail(radix))
|
||||
assertEquals(output, input.convertOrNull(radix))
|
||||
assertEquals(output, convertOrFail(input.removeLeadingPlusOnJava6(), radix))
|
||||
assertEquals(output, convertOrNull(input, radix))
|
||||
}
|
||||
|
||||
fun assertFailsOrNull(radix: Int, input: String) {
|
||||
assertFailsWith<NumberFormatException>("Expected to fail on input \"$input\" with radix $radix",
|
||||
{ input.convertOrFail(radix) })
|
||||
{ convertOrFail(input, radix) })
|
||||
|
||||
assertNull(input.convertOrNull(radix), message = "On input \"$input\" with radix $radix")
|
||||
assertNull(convertOrNull(input, radix), message = "On input \"$input\" with radix $radix")
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
private val isJava6 = System.getProperty("java.version").startsWith("1.6.")
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
private fun String.removeLeadingPlusOnJava6(): String =
|
||||
if (isJava6) removePrefix("+") else this
|
||||
if (isJava6) removePrefix("+") else this
|
||||
|
||||
@kotlin.jvm.JvmVersion
|
||||
private fun doubleTotalOrderEquals(a: Any?, b: Any?) = a == b
|
||||
|
||||
Reference in New Issue
Block a user