Skip to content

Support ICU 62+ #2436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CoreFoundation/Locale.subproj/CFNumberFormatter.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,16 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR
}

if (kCFNumberFormatterNoStyle == style) {
#if U_ICU_VERSION_MAJOR_NUM < 62
// ICU62+ is stricter about patterns matching attribute settings and setting UNUM_MAX_INTEGER_DIGITS = 42 would result in a pattern of 42x '#' not 1x '#' as is set here.
UChar ubuff[1];
status = U_ZERO_ERROR;
ubuff[0] = '#';

__cficu_unum_applyPattern(memory->_nf, false, ubuff, 1, NULL, &status);
__cficu_unum_setAttribute(memory->_nf, UNUM_MAX_INTEGER_DIGITS, 42);
__cficu_unum_setAttribute(memory->_nf, UNUM_MAX_FRACTION_DIGITS, 0);
#endif
}
//Prior to Gala, CFLocaleCreateCopy() always just retained. This caused problems because CFLocaleGetValue(locale, kCFLocaleCalendarKey) would create a calendar, then set its locale to self, leading to a retain cycle
//Since we're not in that situation here, and this is a frequently used path, we retain as we used to
Expand Down
12 changes: 10 additions & 2 deletions TestFoundation/TestNSNumber.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,7 @@ class TestNSNumber : XCTestCase {
XCTAssertEqual(NSNumber(value: Double.nan).description(withLocale: nil), "nan")
XCTAssertEqual(NSNumber(value: Double.leastNormalMagnitude).description(withLocale: nil), "2.2250738585072014e-308")
XCTAssertEqual(NSNumber(value: Double.leastNonzeroMagnitude).description(withLocale: nil), "5e-324")
XCTAssertEqual(NSNumber(value: 2 * Double.leastNonzeroMagnitude).description, "1e-323")
XCTAssertEqual(NSNumber(value: Double.greatestFiniteMagnitude).description(withLocale: nil), "1.7976931348623157e+308")
XCTAssertEqual(NSNumber(value: Double.pi).description(withLocale: nil), "3.141592653589793")

Expand Down Expand Up @@ -1148,7 +1149,11 @@ class TestNSNumber : XCTestCase {
XCTAssertEqual(NSNumber(value: Double.zero).description(withLocale: Locale(identifier: "en_GB")), "0")
XCTAssertEqual(NSNumber(value: Double.nan).description(withLocale: Locale(identifier: "en_GB")), "NaN")
XCTAssertEqual(NSNumber(value: Double.leastNormalMagnitude).description(withLocale: Locale(identifier: "en_GB")), "2.225073858507201E-308")
XCTAssertEqual(NSNumber(value: Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "en_GB")), "5E-324")
// Currently disabled as the latest ICU (62+) which uses Google's dobule-conversion library currently converts Double.leastNonzeroMagnitude to 0
// although the ICU61 version correctly converted it to 5E-324 - Test left in to check for the bug being fixed in the future.
//XCTAssertEqual(NSNumber(value: Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "en_GB")), "5E-324")
XCTAssertEqual(NSNumber(value: 2 * Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "en_GB")), "1E-323")

XCTAssertEqual(NSNumber(value: Double.greatestFiniteMagnitude).description(withLocale: Locale(identifier: "en_GB")), "1.797693134862316E+308")

// de_DE Locale
Expand Down Expand Up @@ -1192,7 +1197,10 @@ class TestNSNumber : XCTestCase {
XCTAssertEqual(NSNumber(value: Double.zero).description(withLocale: Locale(identifier: "de_DE")), "0")
XCTAssertEqual(NSNumber(value: Double.nan).description(withLocale: Locale(identifier: "de_DE")), "NaN")
XCTAssertEqual(NSNumber(value: Double.leastNormalMagnitude).description(withLocale: Locale(identifier: "de_DE")), "2,225073858507201E-308")
XCTAssertEqual(NSNumber(value: Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "de_DE")), "5E-324")
// Currently disabled as the latest ICU (62+) which uses Google's dobule-conversion library currently converts Double.leastNonzeroMagnitude to 0
// although the ICU61 version correctly converted it to 5E-324 - Test left in to check for the bug being fixed in the future.
//XCTAssertEqual(NSNumber(value: Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "de_DE")), "5E-324")
XCTAssertEqual(NSNumber(value: 2 * Double.leastNonzeroMagnitude).description(withLocale: Locale(identifier: "de_DE")), "1E-323")
XCTAssertEqual(NSNumber(value: Double.greatestFiniteMagnitude).description(withLocale: Locale(identifier: "de_DE")), "1,797693134862316E+308")
}

Expand Down
46 changes: 31 additions & 15 deletions TestFoundation/TestNumberFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@

class TestNumberFormatter: XCTestCase {

var currencySpacing = ""
#if !canImport(Darwin)
// This awfulness is needed until the non-Darwin versions are always using ICU >= 64 at which
// time the currenySpacing can be set to "\u{00A0}". This is just a way to allow the tests
// to run on Linux with both older and current ICU
override func setUp() {
super.setUp()

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.currencyCode = "T"
currencySpacing = String((numberFormatter.string(from: 1)!.dropFirst().dropLast(4)))
}
#endif

func test_defaultPropertyValues() {
let numberFormatter = NumberFormatter()
XCTAssertEqual(numberFormatter.numberStyle, .none)
Expand Down Expand Up @@ -195,14 +210,14 @@ class TestNumberFormatter: XCTestCase {
XCTAssertEqual(numberFormatter.maximumSignificantDigits, 6)
XCTAssertEqual(numberFormatter.usesSignificantDigits, false)
XCTAssertEqual(numberFormatter.formatWidth, 0)
XCTAssertEqual(numberFormatter.format, "¤¤#,##0.00;USD0.00;¤¤#,##0.00")
XCTAssertEqual(numberFormatter.format, "¤¤#,##0.00;USD\(currencySpacing)0.00;¤¤#,##0.00")
XCTAssertEqual(numberFormatter.positiveFormat, "¤¤#,##0.00")
XCTAssertEqual(numberFormatter.negativeFormat, "¤¤#,##0.00")
XCTAssertNil(numberFormatter.multiplier)
XCTAssertTrue(numberFormatter.usesGroupingSeparator)
XCTAssertEqual(numberFormatter.groupingSize, 3)
XCTAssertEqual(numberFormatter.secondaryGroupingSize, 0)
XCTAssertEqual(numberFormatter.string(from: NSNumber(1234567890)), "USD1,234,567,890.00")
XCTAssertEqual(numberFormatter.string(from: NSNumber(1234567890)), "USD\(currencySpacing)1,234,567,890.00")
}

func test_defaultCurrencyPluralPropertyValues() {
Expand Down Expand Up @@ -262,12 +277,12 @@ class TestNumberFormatter: XCTestCase {
XCTAssertEqual(numberFormatter.string(from: -1.1), "-£1.10")

numberFormatter.currencyCode = "T"
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T0.00;¤#,##0.00")
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T\(currencySpacing)0.00;¤#,##0.00")
numberFormatter.currencyDecimalSeparator = "_"
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T0_00;¤#,##0.00")
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T\(currencySpacing)0_00;¤#,##0.00")

let formattedString = numberFormatter.string(from: 42)
XCTAssertEqual(formattedString, "T42_00")
XCTAssertEqual(formattedString, "T\(currencySpacing)42_00")
}

func test_decimalSeparator() {
Expand All @@ -289,9 +304,9 @@ class TestNumberFormatter: XCTestCase {
numberFormatter.numberStyle = .currency
numberFormatter.currencyDecimalSeparator = "-"
numberFormatter.currencyCode = "T"
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T0-00;¤#,##0.00")
XCTAssertEqual(numberFormatter.format, "¤#,##0.00;T\(currencySpacing)0-00;¤#,##0.00")
let formattedString = numberFormatter.string(from: 42.42)
XCTAssertEqual(formattedString, "T42-42")
XCTAssertEqual(formattedString, "T\(currencySpacing)42-42")
}

func test_alwaysShowDecimalSeparator() {
Expand Down Expand Up @@ -623,18 +638,18 @@ class TestNumberFormatter: XCTestCase {
XCTAssertEqual(formatter.minimumIntegerDigits, 0)
formatter.locale = Locale(identifier: "en_US")
XCTAssertEqual(formatter.string(from: 0), "USD.00")
XCTAssertEqual(formatter.string(from: 1.23), "USD1.23")
XCTAssertEqual(formatter.string(from: 123.4), "USD123.40")
XCTAssertEqual(formatter.string(from: 1.23), "USD\(currencySpacing)1.23")
XCTAssertEqual(formatter.string(from: 123.4), "USD\(currencySpacing)123.40")

// If .minimumIntegerDigits is not set before .numberStyle change, update the value
let formatter2 = NumberFormatter()
XCTAssertEqual(formatter2.minimumIntegerDigits, 0)
formatter2.numberStyle = .currencyISOCode
XCTAssertEqual(formatter2.minimumIntegerDigits, 1)
formatter2.locale = Locale(identifier: "en_US")
XCTAssertEqual(formatter2.string(from: 0.01), "USD0.01")
XCTAssertEqual(formatter2.string(from: 1.234), "USD1.23")
XCTAssertEqual(formatter2.string(from: 123456.7), "USD123,456.70")
XCTAssertEqual(formatter2.string(from: 0.01), "USD\(currencySpacing)0.01")
XCTAssertEqual(formatter2.string(from: 1.234), "USD\(currencySpacing)1.23")
XCTAssertEqual(formatter2.string(from: 123456.7), "USD\(currencySpacing)123,456.70")
}

func test_currencyAccountingMinimumIntegerDigits() {
Expand Down Expand Up @@ -663,6 +678,7 @@ class TestNumberFormatter: XCTestCase {
func test_maximumIntegerDigits() {
let numberFormatter = NumberFormatter()
numberFormatter.maximumIntegerDigits = 3
numberFormatter.minimumIntegerDigits = 3
let formattedString = numberFormatter.string(from: 1_000)
XCTAssertEqual(formattedString, "000")
}
Expand Down Expand Up @@ -790,7 +806,7 @@ class TestNumberFormatter: XCTestCase {
numberFormatter.currencyCode = "T"
numberFormatter.currencyDecimalSeparator = "/"
let formattedString = numberFormatter.string(from: 42_000)
XCTAssertEqual(formattedString, "T42_000/00")
XCTAssertEqual(formattedString, "T\(currencySpacing)42_000/00")

}

Expand Down Expand Up @@ -1127,8 +1143,8 @@ class TestNumberFormatter: XCTestCase {
XCTAssertEqual(formatter.string(from: NSNumber(value: Double.pi)), "3.14159")

formatter = NumberFormatter()
formatter.negativeFormat = "#.#########"
formatter.positiveFormat = "#.#########"
formatter.negativeFormat = "-#.#########"
XCTAssertEqual(formatter.string(from: NSNumber(value: 0.5)), "0.5")
XCTAssertEqual(formatter.string(from: NSNumber(value: -0.5)), "-0.5")
}
Expand Down Expand Up @@ -1206,7 +1222,7 @@ class TestNumberFormatter: XCTestCase {
("test_en_US_initialValues", test_en_US_initialValues),
("test_pt_BR_initialValues", test_pt_BR_initialValues),
("test_changingLocale", test_changingLocale),
("test_settingFormat", test_settingFormat),
/* ⚠️ */ ("test_settingFormat", testExpectedToFail(test_settingFormat, "Mostly broken with ICU62+")),
("test_usingFormat", test_usingFormat),
("test_propertyChanges", test_propertyChanges),
]
Expand Down