| //===--- 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: %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 |
| } |
| |
| 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) |
| } |
| |
| % end |
| |
| % for Self in 'Float', 'Double', 'Float80': |
| |
| % if Self == 'Float80': |
| #if 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 |
| |
| // Overflow and underflow. Interleave with other checks to make |
| // sure we're not abusing errno |
| expectEqual(0.0, ${Self}("0")) |
| expectNil(${Self}("2e99999999999999")) |
| expectEqual(0.0, ${Self}("0")) |
| expectNil(${Self}("2e-99999999999999")) |
| expectEqual(0.0, ${Self}("0")) |
| expectNil(${Self}("-2e99999999999999")) |
| expectEqual(0.0, ${Self}("0")) |
| expectNil(${Self}("-2e-99999999999999")) |
| expectEqual(0.0, ${Self}("0")) |
| } |
| |
| % if Self == 'Float80': |
| #endif |
| % end |
| |
| % end |
| runAllTests() |