When 50.00 € is not equal to 50.00 € ?!

Hi,


Note: I'm using xcode 6.3.2, deployment target is iOS 8.3.


I'm trying to compare Strings containing currency symbols (namely the euro symbol). I wrote the following test:

        // Given
        let price = Money(amount: 50)
  
        // When
        let priceTag = price.format()
       
        // Then
        let expectedPriceTag = "50,00 €"    
        XCTAssertEqual(expectedPriceTag, priceTag, "Invalid formatting")


The Money format method is basically:

        NSNumberFormatter.localizedStringFromNumber(amount, numberStyle: .CurrencyStyle)


The expectedPriceTag euro symbol is inserted using the Edit > Emoji & Symbols menu of xcode.

When running the test, I get the following failure message:

/Users/brieuc/Projects/Nestor/Nestor-iOS-Swift/NestorTests/MoneyTest.swift:104: error: -[NestorTests.MoneyTest testFormat2] : 
XCTAssertEqual failed: ("50,00 €") is not equal to ("50,00 €") - Invalid formatting


I've looked twice but... yeah it's real. After looking at the content of the strings, it turns out that both strings have the same number of unicode scalars but differ by one...

priceTag: 53 48 44 48 48 160 8364

expectedPriceTag: 53 48 44 48 48 32 8364


So the NSNumberFormatter.localizedStringFromNumber with currency style inserts a unicode scalar with value 160 as a whitespace...

What should I do to make my code pass the test reliably ?


I've tried to insert this unicode scalar instead of a whitespace in expectedPriceTag but it does give me what I expected...


Any help and/or background info on how to fix this would be greatly appreciated


Thanks

32 is a normal ASCII / Unicode code point for a space.

160 is the Unicode code point for a non-breaking space (see https://en.wikipedia.org/wiki/Non-breaking_space) for details. The difference is that a non-breaking space displays as a space but is not a valid place for a line break in case the text is split over multiple rows.


You can probably change your current local (country/lanuage/currency settings) while the test is run, this would ensure that you get predictable strings from the format() call.

This gotcha has bitten folks before. The U+00A0 is a non-breaking space, which makes sense because you don't want the value and the currency symbol to get split across a line break. You should be able to fix your test by putting a non-breakpoint space in your expectedPriceTag string. Use Swift's "\u{xxxx}" notation.


btw Your test seems locale sensitive, which could be a problem if someone else runs your test. Even if you're limited to countries that use the Euro, not all countries use 50,00 €. For example, in Ireland this would be €50.00.


Share and Enjoy

--

Quinn "The Eskimo!"

Apple Developer Relations, Developer Technical Support, Core OS/Hardware

When 50.00 € is not equal to 50.00 € ?!
 
 
Q