mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-11 21:27:11 +00:00
CPScanner fixes with tests.
This commit is contained in:
+51
-126
@@ -16,41 +16,6 @@
|
||||
CPCharacterSet _charactersToBeSkipped;
|
||||
}
|
||||
|
||||
// TODO Not all methods of NSScanner are available!
|
||||
|
||||
/*
|
||||
- (BOOL)scanLongLong:(long long *)longLongValue
|
||||
{
|
||||
}
|
||||
- (BOOL)scanDecimal:(NSDecimal *)decimalValue
|
||||
{
|
||||
}
|
||||
- (BOOL)scanHexDouble:(double *)result
|
||||
{
|
||||
}
|
||||
- (BOOL)scanHexFloat:(float *)result
|
||||
{
|
||||
}
|
||||
- (BOOL)scanHexInt:(unsigned *)intValue
|
||||
{
|
||||
}
|
||||
- (BOOL)scanHexLongLong:(unsigned long long *)result
|
||||
{
|
||||
}
|
||||
- (BOOL)scanInteger:(NSInteger *)value
|
||||
{
|
||||
}
|
||||
+ (id)localizedScannerWithString:(CPString)string
|
||||
{
|
||||
var scanner = [self scannerWithString:string];
|
||||
|
||||
[scanner setLocale:[CPLocale currentLocale]];
|
||||
|
||||
return scanner;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
+ (id)scannerWithString:(CPString)aString
|
||||
{
|
||||
return [[self alloc] initWithString:aString];
|
||||
@@ -72,12 +37,12 @@
|
||||
- (id)copy
|
||||
{
|
||||
var copy = [[CPScanner alloc] initWithString:[self string]];
|
||||
|
||||
|
||||
[copy setCharactersToBeSkipped:[self charactersToBeSkipped]];
|
||||
[copy setCaseSensitive:[self caseSensitive]];
|
||||
[copy setLocale:[self locale]];
|
||||
[copy setScanLocation:[self scanLocation]];
|
||||
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -140,10 +105,10 @@
|
||||
- (BOOL)_performScanWithSelector:(SEL)s withObject:(id)arg into:(id)ref
|
||||
{
|
||||
var ret = [self performSelector:s withObject:arg];
|
||||
|
||||
|
||||
if (ret == nil)
|
||||
return NO;
|
||||
|
||||
|
||||
if (ref != nil)
|
||||
ref(ret);
|
||||
|
||||
@@ -182,14 +147,14 @@
|
||||
{
|
||||
if ([self isAtEnd])
|
||||
return nil;
|
||||
|
||||
var current = [self scanLocation];
|
||||
var str = nil;
|
||||
|
||||
|
||||
var current = [self scanLocation],
|
||||
str = nil;
|
||||
|
||||
while (current < _string.length)
|
||||
{
|
||||
var c = (_string.charAt(current));
|
||||
|
||||
|
||||
if ([scanSet characterIsMember:c] == stop)
|
||||
break;
|
||||
|
||||
@@ -199,13 +164,13 @@
|
||||
str = '';
|
||||
str += c;
|
||||
}
|
||||
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
|
||||
if (str)
|
||||
[self setScanLocation:current];
|
||||
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -215,18 +180,18 @@
|
||||
|
||||
- (void)_movePastCharactersToBeSkipped
|
||||
{
|
||||
var current = [self scanLocation];
|
||||
var string = [self string];
|
||||
var toSkip = [self charactersToBeSkipped];
|
||||
|
||||
var current = [self scanLocation],
|
||||
string = [self string],
|
||||
toSkip = [self charactersToBeSkipped];
|
||||
|
||||
while (current < string.length)
|
||||
{
|
||||
if (![toSkip characterIsMember:string.charAt(current)])
|
||||
break;
|
||||
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
|
||||
[self setScanLocation:current];
|
||||
}
|
||||
|
||||
@@ -261,29 +226,31 @@
|
||||
|
||||
- (CPString)scanUpToString:(CPString)s
|
||||
{
|
||||
var current = [self scanLocation], str = [self string];
|
||||
var captured = nil;
|
||||
var current = [self scanLocation],
|
||||
str = [self string],
|
||||
captured = nil;
|
||||
|
||||
while (current < str.length)
|
||||
{
|
||||
var currentStr = str.substr(current, s.length);
|
||||
if (currentStr == s || (!_caseSensitive && currentStr.toLowerCase() == s.toLowerCase()))
|
||||
break;
|
||||
|
||||
|
||||
if (!captured)
|
||||
captured = '';
|
||||
captured += str.charAt(current);
|
||||
current++;
|
||||
}
|
||||
|
||||
|
||||
if (captured)
|
||||
[self setScanLocation:current];
|
||||
|
||||
|
||||
// evil private method use!
|
||||
// this method is defined in the category on CPString
|
||||
// in CPCharacterSet.j
|
||||
if ([self charactersToBeSkipped])
|
||||
captured = [captured _stringByTrimmingCharactersInSet:[self charactersToBeSkipped] options:_CPCharacterSetTrimAtBeginning];
|
||||
|
||||
|
||||
return captured;
|
||||
}
|
||||
|
||||
@@ -291,81 +258,39 @@
|
||||
/* = Scanning numbers = */
|
||||
/* ==================== */
|
||||
|
||||
- (float)scanFloat
|
||||
- (float)scanWithParseFunction:(Function)parseFunction
|
||||
{
|
||||
[self _movePastCharactersToBeSkipped];
|
||||
var str = [self string], current = [self scanLocation];
|
||||
|
||||
var str = [self string],
|
||||
loc = [self scanLocation];
|
||||
|
||||
if ([self isAtEnd])
|
||||
return 0;
|
||||
|
||||
var s = str.substring(current, str.length);
|
||||
var f = parseFloat(s); // wont work with non . decimal separator !!
|
||||
if (f)
|
||||
{
|
||||
var pos, foundDash = NO;
|
||||
/*
|
||||
var decimalSeparatorString;
|
||||
if(_locale != nil)
|
||||
decimalSeparatorString = [_locale objectForKey:CPLocaleDecimalSeparator];
|
||||
else
|
||||
decimalSeparatorString = [[CPLocale systemLocale] objectForKey:CPLocaleDecimalSeparator];
|
||||
|
||||
var separatorCode = (decimalSeparatorString.length >0) decimalSeparatorString.charCodeAt(0) : 45;
|
||||
*/
|
||||
var separatorCode = 45;
|
||||
|
||||
for(pos = current; pos < current + str.length; pos++)
|
||||
{
|
||||
var charCode = str.charCodeAt(pos);
|
||||
if (charCode == separatorCode)
|
||||
{
|
||||
if (foundDash == YES)
|
||||
break; // We already found a decimal separator so this one is an extra char
|
||||
foundDash = YES;
|
||||
}
|
||||
else if (charCode < 48 || charCode > 57 || (charCode == 45 && pos != current)) // not a digit or a "-" but not prefix
|
||||
break;
|
||||
}
|
||||
|
||||
[self setScanLocation:pos];
|
||||
return f;
|
||||
}
|
||||
|
||||
return nil;
|
||||
var s = str.substring(loc, str.length),
|
||||
f = parseFunction(s);
|
||||
|
||||
if (isNaN(f))
|
||||
return nil;
|
||||
|
||||
loc += (""+f).length;
|
||||
var i = 0;
|
||||
while (!isNaN(parseFloat(str.substring(loc+i, str.length))))
|
||||
{i++;}
|
||||
|
||||
[self setScanLocation:loc + i];
|
||||
return f;
|
||||
|
||||
}
|
||||
|
||||
- (float)scanFloat
|
||||
{
|
||||
return [self scanWithParseFunction:parseFloat];
|
||||
}
|
||||
|
||||
- (int)scanInt
|
||||
{
|
||||
[self _movePastCharactersToBeSkipped];
|
||||
var str = [self string], current = [self scanLocation];
|
||||
|
||||
if ([self isAtEnd])
|
||||
return 0;
|
||||
var s = str.substring(current, str.length);
|
||||
|
||||
var i = parseInt(s);
|
||||
if (i)
|
||||
{
|
||||
var pos, foundDash = NO;
|
||||
for (pos = current; pos < current + str.length; pos++)
|
||||
{
|
||||
var charCode = str.charCodeAt(pos);
|
||||
if (charCode == 46)
|
||||
{
|
||||
if (foundDash == YES)
|
||||
break;
|
||||
foundDash = YES;
|
||||
}
|
||||
else if (charCode < 48 || charCode > 57 || (charCode == 45 && pos != current))
|
||||
break;
|
||||
}
|
||||
|
||||
[self setScanLocation:pos];
|
||||
return i;
|
||||
}
|
||||
|
||||
return nil;
|
||||
return [self scanWithParseFunction:parseInt];
|
||||
}
|
||||
|
||||
- (BOOL)scanInt:(int)intoInt
|
||||
@@ -392,4 +317,4 @@
|
||||
return [super description] + " {" + CPStringFromClass([self class]) + ", state = '" + ([self string].substr(0, _scanLocation) + "{{ SCAN LOCATION ->}}" + [self string].substr(_scanLocation)) + "'; }";
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,25 +1,74 @@
|
||||
@import <Foundation/Foundation.j>
|
||||
|
||||
@import <Foundation/CPScanner.j>
|
||||
|
||||
@implementation CPScannerTest : OJTestCase
|
||||
|
||||
- (void)performScanMethod:(SEL)selector searchFor:(id)search inScanner:(CPString)scanner succeeded:(BOOL)success found:/*accumulated result or nil if nothing should be accumulated*/(id)accumulator endedAt:(int)endLocation
|
||||
{
|
||||
if ([scanner isKindOfClass:[CPString class]])
|
||||
scanner = [CPScanner scannerWithString:scanner];
|
||||
|
||||
var objj_args = [scanner, selector],
|
||||
value = @"initialValue";
|
||||
|
||||
if (accumulator == nil)
|
||||
accumulator = value;
|
||||
|
||||
if (search != nil)
|
||||
objj_args.push(search);
|
||||
|
||||
objj_args.push(function(v){value = v;});
|
||||
|
||||
var didScan = objj_msgSend.apply(this, objj_args);
|
||||
|
||||
[self assert:success equals:didScan message:scanner + " Scan operation: "];
|
||||
[self assert:accumulator equals:value message:scanner + " Accumulator: "];
|
||||
if (endLocation != nil)
|
||||
[self assert:endLocation equals:[scanner scanLocation] message:scanner + " Scan location: "];
|
||||
}
|
||||
|
||||
- (void)testNothingScanned
|
||||
- (void)testScanInt
|
||||
{
|
||||
var x = @"x",
|
||||
str = x,
|
||||
scanner,
|
||||
result;
|
||||
|
||||
scanner = [CPScanner scannerWithString:@"a"];
|
||||
result = [scanner scanString:@"b" intoString:str];
|
||||
[self assertFalse:result message:"Result should be FALSE"];
|
||||
[self assertTrue:str === x message:"The string passed by reference should not change, is " + str];
|
||||
|
||||
scanner = [CPScanner scannerWithString:@"a"];
|
||||
result = [scanner scanUpToString:@"a" intoString:str];
|
||||
[self assertFalse:result message:"Result should be FALSE"];
|
||||
[self assertTrue:str === x message:"The string passed by reference should not change, is " + str];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@"1" succeeded:YES found:1 endedAt:1];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@" 12" succeeded:YES found:12 endedAt:3];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@"01" succeeded:YES found:1 endedAt:2];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@"131F02" succeeded:YES found:131 endedAt:3];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@"word" succeeded:NO found:nil endedAt:0];
|
||||
[self performScanMethod:@selector(scanInt:) searchFor:nil inScanner:@"0S" succeeded:YES found:0 endedAt:1];
|
||||
}
|
||||
|
||||
- (void)testScanFloat
|
||||
{
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"1" succeeded:YES found:1 endedAt:1];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"1.2" succeeded:YES found:1.2 endedAt:3];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"-1.2" succeeded:YES found:-1.2 endedAt:4];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"1.2x" succeeded:YES found:1.2 endedAt:3];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"word" succeeded:NO found:nil endedAt:0];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"0.00" succeeded:YES found:0 endedAt:4];
|
||||
|
||||
// wrong end location
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@".1-2" succeeded:YES found:0.1 endedAt:nil];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"1.2.3" succeeded:YES found:1.2 endedAt:nil];
|
||||
[self performScanMethod:@selector(scanFloat:) searchFor:nil inScanner:@"-1.2-3" succeeded:YES found:-1.2 endedAt:nil];
|
||||
}
|
||||
|
||||
- (void)testScanString
|
||||
{
|
||||
[self performScanMethod:@selector(scanString:intoString:) searchFor:@"t" inScanner:@"topaz" succeeded:YES found:@"t" endedAt:1];
|
||||
[self performScanMethod:@selector(scanString:intoString:) searchFor:@"z" inScanner:@"topaz" succeeded:NO found:nil endedAt:0];
|
||||
[self performScanMethod:@selector(scanString:intoString:) searchFor:@"tt" inScanner:@"topaz" succeeded:NO found:nil endedAt:0];
|
||||
|
||||
[self performScanMethod:@selector(scanUpToString:intoString:) searchFor:@"a" inScanner:@"topaz" succeeded:YES found:@"top" endedAt:3];
|
||||
[self performScanMethod:@selector(scanUpToString:intoString:) searchFor:@"x" inScanner:@"topaz" succeeded:YES found:@"topaz" endedAt:5];
|
||||
[self performScanMethod:@selector(scanUpToString:intoString:) searchFor:@"x" inScanner:@"" succeeded:NO found:nil endedAt:0];
|
||||
}
|
||||
|
||||
- (void)testScanCharactersFromSet
|
||||
{
|
||||
[self performScanMethod:@selector(scanCharactersFromSet:intoString:) searchFor:[CPCharacterSet lowercaseLetterCharacterSet] inScanner:@"topAz" succeeded:YES found:@"top" endedAt:3];
|
||||
|
||||
[self performScanMethod:@selector(scanCharactersFromSet:intoString:) searchFor:[CPCharacterSet alphanumericCharacterSet] inScanner:@"top12Az&x" succeeded:YES found:@"top12Az" endedAt:7];
|
||||
[self performScanMethod:@selector(scanCharactersFromSet:intoString:) searchFor:[CPCharacterSet decomposableCharacterSet] inScanner:@"êñço" succeeded:YES found:@"êñç" endedAt:3];
|
||||
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user