From 7bef84e4e99ffe8f8595dedb90b5e85c099626ab Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Thu, 7 Mar 2013 00:26:02 -0500 Subject: [PATCH] Allow CPDecimal to handle decimal numbers with leading zeros Without this fix, CPDecimal will return NaN for numbers that have leading zeros, e.g., 0123. This fix changes the matching regex to allow leading zeros to pass. This is then converted to a proper number later on, e.g., "0123" => 123. This is in line with Cocoa behaviour. This commit also includes updated unit tests. --- Foundation/CPDecimal.j | 4 ++-- Tests/Foundation/CPDecimalNumberTest.j | 10 +++++----- Tests/Foundation/CPDecimalTest.j | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Foundation/CPDecimal.j b/Foundation/CPDecimal.j index a38e556bb..15d2f817d 100644 --- a/Foundation/CPDecimal.j +++ b/Foundation/CPDecimal.j @@ -108,7 +108,7 @@ function CPDecimalMakeWithString(string, locale) // Regexp solution as found in JSON spec, with working regexp (I added groupings) // Test here: http://www.regexplanet.com/simple/index.html // Info from: http://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly - // ([+\-]?)((?:0|[1-9]\d*)) - integer part, cant have leading zeros + // ([+\-]?)((?:0|[0-9]\d*)) - integer part, can have leading zeros (follows Cocoa behaviour) // (?:\.(\d*))? - optional decimal part plus number in group // (?:[eE]([+\-]?)(\d+))? - optional exponent part plus number in group // group 0: string, 1: sign, 2: integer, 3: decimal, 4: exponent sign, 5: exponent @@ -116,7 +116,7 @@ function CPDecimalMakeWithString(string, locale) // Note: this doesn't accept .01 for example, should it? // If yes simply add '?' after integer part group, i.e. ([+\-]?)((?:0|[1-9]\d*)?) // Note: now it accept .01 style. - var matches = string.match(/^([+\-]?)((?:0|[1-9]\d*)?)(?:\.(\d*))?(?:[eE]([+\-]?)(\d+))?$/); + var matches = string.match(/^([+\-]?)((?:0|[0-9]\d*)?)(?:\.(\d*))?(?:[eE]([+\-]?)(\d+))?$/); if (!matches) return CPDecimalMakeNaN(); diff --git a/Tests/Foundation/CPDecimalNumberTest.j b/Tests/Foundation/CPDecimalNumberTest.j index 724953039..c85873245 100644 --- a/Tests/Foundation/CPDecimalNumberTest.j +++ b/Tests/Foundation/CPDecimalNumberTest.j @@ -130,6 +130,9 @@ [self assert:[0] equals:dcm._mantissa message:"zero: - mantissa"]; [self assert:NO equals:dcm._isNegative message:"zero: - sign"]; + // this is Cocoa behaviour -- convert a decimal number with a leading zero to a number. + dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"]; + [self assertTrue:[dcmn isEqualToNumber:123]]; // misc // decimalValue <- if it hasnt been working so far, you would know. @@ -147,14 +150,11 @@ dcmn = [[CPDecimalNumber alloc] initWithString:@"foo"]; [self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 2 overflow should return NaN"]; - dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"]; + dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"]; [self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 3 overflow should return NaN"]; - dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"]; - [self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 4 overflow should return NaN"]; - dcmn = [[CPDecimalNumber alloc] initWithString:@"12312e-23421"]; - [self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 5 overflow should return NaN"]; + [self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 4 overflow should return NaN"]; } - (void)testAdd diff --git a/Tests/Foundation/CPDecimalTest.j b/Tests/Foundation/CPDecimalTest.j index 6ba4c5fb1..7f88d8c14 100644 --- a/Tests/Foundation/CPDecimalTest.j +++ b/Tests/Foundation/CPDecimalTest.j @@ -68,7 +68,7 @@ [self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf4: NaN is incorrectly set"]; dcm = CPDecimalMakeWithString(@"000000000000000000"); - [self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Tf5: Should be invalid"]; + [self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Tf5: Should be valid"]; // too large return NaN dcm = CPDecimalMakeWithString(@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); @@ -95,10 +95,12 @@ [self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti7: catch of invalid number string. Should return NaN"]; dcm = CPDecimalMakeWithString(@"123ee"); [self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti8: catch of invalid number string. Should return NaN"]; + + // this behaviour has changed to match Cocoa. Making a decimal with a leading zero should return the decimal. dcm = CPDecimalMakeWithString(@"0001"); - [self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti9: catch of invalid number string. Should return NaN"]; + [self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Ti9: Numbers with leading zeros are valid numbers. Expected False when evaluating against NaN, got True."]; dcm = CPDecimalMakeWithString(@"-0001"); - [self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti10: catch of invalid number string. Should return NaN"]; + [self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Ti10: Numbers with leading zeros are valid numbers. Expected False when evaluating against NaN, got True."]; //test make with parts dcm = CPDecimalMakeWithParts(10127658, 2);