//===--- NumericParsing.swift.gyb -----------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // -*- swift -*- // RUN: %empty-directory(%t) // RUN: %gyb -DCMAKE_SIZEOF_VOID_P=%target-ptrsize %s -o %t/NumericParsing.swift // RUN: %line-directive %t/NumericParsing.swift -- %target-build-swift %t/NumericParsing.swift -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %line-directive %t/NumericParsing.swift -- %target-run %t/a.out // REQUIRES: executable_test %{ from SwiftIntTypes import all_integer_types word_bits = int(CMAKE_SIZEOF_VOID_P) def maskOfWidth(n): return (1 << n) - 1 def inRadix(radix, n, zero='0'): """ Represent the int n in the given radix. Note: the third parameter, zero, is not for user consumption. """ if n < 0: return '-' + inRadix(radix, -n, '') elif n == 0: return zero else: r = n % radix digit = chr((ord('0') + r) if r < 10 else (ord('a') + r - 10)) return inRadix(radix, int(n // radix), '') + digit # The maximal legal radix max_radix = ord('z') - ord('a') + 1 + 10 # Test a few important radices radices_to_test = [2, 8, 10, 16, max_radix] # How many values to test in each radix? A nice prime number of course. number_of_values = 23 }% import StdlibUnittest var tests = TestSuite("NumericParsing") % for type in all_integer_types(word_bits): % Self = type.stdlib_name % maxValue = maskOfWidth((type.bits - 1) if type.is_signed else type.bits) % minValue = -maxValue - 1 if type.is_signed else 0 % required_values = [minValue, 0, maxValue] tests.test("${Self}/success") { let isSigned = ${str(type.is_signed).lower()} //===--- Important cases ------------------------------------------------===// expectEqual(0, ${Self}("0")) // zero expectEqual(17, ${Self}("17")) // non-zero with no radix // Leading zeroes, with and without a radix expectEqual(10, ${Self}("010")) expectEqual(15, ${Self}("00F", radix: 16)) // Leading '+' expectEqual(0, ${Self}("+0")) expectEqual(10, ${Self}("+10")) expectEqual(10, ${Self}("+010")) expectEqual(15, ${Self}("+00F", radix: 16)) // Negative numbers expectEqual(${-128 if type.is_signed else 'nil'}, ${Self}("-0080", radix: 16)) expectEqual(0, ${Self}("-0")) expectEqual(0, ${Self}("-00", radix: 16)) // Maximum radix expectEqual(${max_radix} - 1, ${Self}("z", radix: ${max_radix})!) // Out-of-range values expectEqual(nil, ${Self}("${maxValue + 1}")) expectEqual(nil, ${Self}("${minValue - 1}")) expectEqual(nil, ${Self}("\u{1D7FF}")) // MATHEMATICAL MONOSPACE DIGIT NINE // Cases that should fail to parse expectEqual(nil, ${Self}("--0")) // Zero w/ repeated plus expectEqual(nil, ${Self}("-+5")) // Non-zero with -+ // Do more exhaustive testing % for radix in radices_to_test: % for n in required_values + list(range( % minValue + 1, maxValue - 1, % int((maxValue - minValue - 2) // (number_of_values - len(required_values))))): % prefix = '+' if n > 0 and n % 2 == 0 else '' # leading '+' % text = inRadix(radix, n) expectEqual(${n}, ${Self}("${prefix + text}", radix: ${radix})) % if text != text.upper(): expectEqual(${n}, ${Self}("${prefix + text.upper()}", radix: ${radix})) % end % end % end } #if !os(WASI) // Trap tests aren't available on WASI. tests.test("${Self}/radixTooLow") { ${Self}("0", radix: 2) expectCrashLater() ${Self}("0", radix: 1) } tests.test("${Self}/radixTooHigh") { let maxRadix = ${ord('z') - ord('a') + 1 + 10} ${Self}("0", radix: maxRadix) expectCrashLater() let y = ${Self}("0", radix: maxRadix + 1) } #endif % end tests.test("FixedWidthInteger/maxUInt64") { func f(_ x: T) -> String { return String(x, radix: 16) } let x = f(UInt64.max) let y = String(UInt64.max, radix: 16) expectEqual(x, y) } % for Self in 'Float', 'Double', 'Float80': % if Self == 'Float80': #if !os(Windows) && (arch(i386) || arch(x86_64)) % end tests.test("${Self}/Basics") { % if Self != 'Float80': # Inf/NaN are not defined for Float80 expectEqual(.infinity, ${Self}("inf")) expectEqual(.infinity, ${Self}("Inf")) expectEqual(-(.infinity), ${Self}("-inf")) expectEqual(-(.infinity), ${Self}("-Inf")) expectEqual(String(${Self}.nan), String(${Self}("nan")!)) expectEqual(String(${Self}.nan), String(${Self}("NaN")!)) // sNaN cannot be fully supported on i386. #if !arch(i386) expectTrue(${Self}("sNaN")!.isSignalingNaN) expectTrue(${Self}("SNAN")!.isSignalingNaN) expectTrue(${Self}("+snan")!.isSignalingNaN) expectTrue(${Self}("-SnAn")!.isSignalingNaN) #endif % end expectEqual(-0.0, ${Self}("-0")) expectEqual(-0.0, ${Self}("-0.0")) expectEqual(0.0, ${Self}("0")) expectEqual(0.0, ${Self}("0.0")) expectEqual(64206, ${Self}("0xFACE")) // Yes, strtoXXX supports hex. // Check that we can round-trip the string representation of 2^100, // which requires an exponent to express... let large = repeatElement(1024 as ${Self}, count: 10).reduce(1, *) let largeText = String(large) expectEqual(largeText, String(${Self}(largeText)!)) // ...ditto for its inverse. let smallText = String(1 / large) expectEqual(smallText, String(${Self}(smallText)!)) // Cases that should fail to parse expectNil(${Self}("")) // EMPTY expectNil(${Self}("0FACE")) // Hex characters without 0x expectNil(${Self}("99x")) expectNil(${Self}(" 0")) // Leading whitespace expectNil(${Self}("0 ")) // Trailing whitespace expectNil(${Self}("\u{1D7FF}")) // MATHEMATICAL MONOSPACE DIGIT NINE // Values that are too large/small: // * Early versions of Swift returned `nil` for e.g., 1e99999 or 1e-99999 // * After 5.3, large/small values return .infinity or zero, respectively // These are tested in NumericParsing2.swift.gyb } % if Self == 'Float80': #endif % end % end runAllTests()