Hello everyone,
Some unit tests have started failing only when ran on iOS 10, iOS Simulator, while they still succeed for iOS 8 and iOS 9 (same device type, but different OS).
The way to make the number formatter work is quite surreal though (I essentially have to format an amount into a string, set a property on the formatter [it does not matter if I set it before or not], and then formatting the same number into a string).
Unit test:
- (void)testLegacyFormatCurrencyInGame_demoModeNo_forceDecimalsYes_splitThousandsNo_hideCurrencySymbolNo_addTrailingZerosNo_GreaterThanOne
{
NSNumber *amount = @(50);
NSString *expectedFormattedString = [NSString stringWithFormat:@"%@50", self.largeCurrencySymbol];
BOOL demoMode = NO;
BOOL forceDecimals = YES;
BOOL splitThousands = NO;
BOOL hideCurrencySymbol = NO;
BOOL addTrailingZeros = NO;
CurrencyModel *configParameters = [self currencyModelWithAmount:amount
addTrailingZeros:addTrailingZeros
forceDecimals:forceDecimals
splitThrousands:splitThousands
hideCurrencySymbol:hideCurrencySymbol
demoMode:demoMode];
NSString *convertedString = [self.accountLogic formatCurrencyInGame:amount
withLegacySettings:configParameters];
XCTAssertTrue([expectedFormattedString isEqualToString:convertedString],
@"expected %@, received %@", expectedFormattedString, convertedString);
}Actual implementation (version that passes the test):
// It is important to note that this one handles in game currency code a little bit differently.
// This code handles the Lua specification as specified in host events v01
- (NSString *)formatCurrencyInGame:(NSNumber *)amount
withLegacySettings:(CurrencyModel *)settings
{
if (amount == nil) {
return kEmptyString;
}
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setLocale:[self memberLocale]];
BOOL forceDecimals = NO;
BOOL addTrailingZeros = NO;
BOOL hideCurrencySymbol = NO;
BOOL splitThousands = NO;
if (settings != nil) {
forceDecimals = settings.forceDecimals;
addTrailingZeros = settings.addTrailingZeros;
hideCurrencySymbol = settings.hideCurrencySymbols;
splitThousands = settings.splitThousands;
}
if (hideCurrencySymbol == YES) {
[formatter setCurrencySymbol:kEmptyString];
}
if (splitThousands == NO) {
[formatter setCurrencyGroupingSeparator:kEmptyString];
}
if ([amount doubleValue] < 1.0 && forceDecimals == YES) {
// Ensure that if we are using NO currency symbol (i.e. demo mode) we don't do any of this.
if (hideCurrencySymbol == YES) {
return [formatter stringFromNumber:amount];
}
[formatter setCurrencySymbol:kEmptyString];
[formatter setMultiplier:@100.0];
[formatter setMaximumFractionDigits:0];
return [NSString stringWithFormat:@"%@%@", [formatter stringFromNumber:amount], [self smallCurrencySymbol]];
}
if ([amount doubleValue] >= 1.0) {
if ( addTrailingZeros == YES ) {
[formatter setMinimumFractionDigits:2];
} else {
// Truncate all decimal places unless we intend on printing a cent value.
double value = [amount doubleValue];
if (((value * 100.0) - (floor(value) * 100.0)) < 0.5) {
[formatter setMaximumFractionDigits:0];
}
}
}
NSString *formattedString = [formatter stringFromNumber:amount];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0") &&
formatter.maximumFractionDigits < 1) {
formatter.minimumFractionDigits = 0;
formattedString = [formatter stringFromNumber:amount];
}
return formattedString;
}Actual implementation (version that fails the test):
// It is important to note that this one handles in game currency code a little bit differently.
// This code handles the Lua specification as specified in host events v01
- (NSString *)formatCurrencyInGame:(NSNumber *)amount
withLegacySettings:(CurrencyModel *)settings
{
if (amount == nil) {
return kEmptyString;
}
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setLocale:[self memberLocale]];
BOOL forceDecimals = NO;
BOOL addTrailingZeros = NO;
BOOL hideCurrencySymbol = NO;
BOOL splitThousands = NO;
if (settings != nil) {
forceDecimals = settings.forceDecimals;
addTrailingZeros = settings.addTrailingZeros;
hideCurrencySymbol = settings.hideCurrencySymbols;
splitThousands = settings.splitThousands;
}
if (hideCurrencySymbol == YES) {
[formatter setCurrencySymbol:kEmptyString];
}
if (splitThousands == NO) {
[formatter setCurrencyGroupingSeparator:kEmptyString];
}
if ([amount doubleValue] < 1.0 && forceDecimals == YES) {
// Ensure that if we are using NO currency symbol (i.e. demo mode) we don't do any of this.
if (hideCurrencySymbol == YES) {
return [formatter stringFromNumber:amount];
}
[formatter setCurrencySymbol:kEmptyString];
[formatter setMultiplier:@100.0];
[formatter setMaximumFractionDigits:0];
return [NSString stringWithFormat:@"%@%@", [formatter stringFromNumber:amount], [self smallCurrencySymbol]];
}
if ([amount doubleValue] >= 1.0) {
if ( addTrailingZeros == YES ) {
[formatter setMinimumFractionDigits:2];
} else {
// Truncate all decimal places unless we intend on printing a cent value.
double value = [amount doubleValue];
if (((value * 100.0) - (floor(value) * 100.0)) < 0.5) {
[formatter setMaximumFractionDigits:0];
}
}
}
NSString *formattedString = [formatter stringFromNumber:amount];
return formattedString;
}This is quite odd... A bug? I have not seen anything in the docs to suggest there was such a change required for NSNumberFormatter...