From cdf070c8d76ffc4eaa24e8671756cbbe9ceb2890 Mon Sep 17 00:00:00 2001 From: thomasvl Date: Mon, 14 Apr 2008 17:21:02 +0000 Subject: See the ReleaseNotes for the full details, highlights: - bug fixes - code coverage support - more complete unittests - full support for unittesting UIs - support for the iphone sdk (include ui unittesting) --- Foundation/GTMRegex.m | 132 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 29 deletions(-) (limited to 'Foundation/GTMRegex.m') diff --git a/Foundation/GTMRegex.m b/Foundation/GTMRegex.m index d7900fa..c50ff2b 100644 --- a/Foundation/GTMRegex.m +++ b/Foundation/GTMRegex.m @@ -16,7 +16,9 @@ // the License. // +#define GTMREGEX_DEFINE_GLOBALS 1 #import "GTMRegex.h" +#import "GTMDefines.h" // This is the pattern to use for walking replacement text when doing // substitutions. @@ -71,6 +73,14 @@ static NSString *const kReplacementPattern = options:options] autorelease]; } ++ (id)regexWithPattern:(NSString *)pattern + options:(GTMRegexOptions)options + withError:(NSError **)outErrorOrNULL { + return [[[self alloc] initWithPattern:pattern + options:options + withError:outErrorOrNULL] autorelease]; +} + + (NSString *)escapedPatternForString:(NSString *)str { if (str == nil) return nil; @@ -117,9 +127,18 @@ static NSString *const kReplacementPattern = } - (id)initWithPattern:(NSString *)pattern options:(GTMRegexOptions)options { + return [self initWithPattern:pattern options:options withError:nil]; +} + +- (id)initWithPattern:(NSString *)pattern + options:(GTMRegexOptions)options + withError:(NSError **)outErrorOrNULL { + self = [super init]; if (!self) return nil; + if (outErrorOrNULL) *outErrorOrNULL = nil; + if ([pattern length] == 0) { [self release]; return nil; @@ -138,17 +157,31 @@ static NSString *const kReplacementPattern = // error info). we use pattern_ as this flag. pattern_ = [pattern copy]; if (!pattern_) { + // COV_NF_START - no real way to force this in a unittest [self release]; return nil; + // COV_NF_END } // compile it int compResult = regcomp(®exData_, [pattern_ UTF8String], flags); if (compResult != 0) { - // we don't want to throw if we failed, so we'll return nil, but still - // log the error just so it's out there. NSString *errorStr = [self errorMessage:compResult]; - NSLog(@"Invalid pattern \"%@\", error: \"%@\"", pattern_, errorStr); + if (outErrorOrNULL) { + // include the pattern and patternError message in the userInfo. + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + pattern_, kGTMRegexPatternErrorPattern, + errorStr, kGTMRegexPatternErrorErrorString, + nil]; + *outErrorOrNULL = [NSError errorWithDomain:kGTMRegexErrorDomain + code:kGTMRegexPatternParseFailedError + userInfo:userInfo]; + } else { + // if caller didn't get us an NSError to fill in, we log the error to help + // debugging. + _GTMDevLog(@"Invalid pattern \"%@\", error: \"%@\"", + pattern_, errorStr); + } [self release]; return nil; @@ -193,7 +226,7 @@ static NSString *const kReplacementPattern = int count = regexData_.re_nsub + 1; regmatch_t *regMatches = malloc(sizeof(regmatch_t) * count); if (!regMatches) - return nil; + return nil; // COV_NF_LINE - no real way to force this in a unittest // wrap it all in a try so we don't leak the malloc @try { @@ -232,7 +265,7 @@ static NSString *const kReplacementPattern = } result = buildResult; - } + } // COV_NF_LINE - radar 5851992 not all brackets reachable w/ obj-c exceptions and coverage @finally { free(regMatches); } @@ -240,6 +273,38 @@ static NSString *const kReplacementPattern = return result; } +- (NSString *)firstSubStringMatchedInString:(NSString *)str { + NSString *result = nil; + + regmatch_t regMatch; + const char *utf8Str = [str UTF8String]; + if ([self runRegexOnUTF8:utf8Str + nmatch:1 + pmatch:®Match + flags:0]) { + // fetch the string + const char *base = utf8Str + regMatch.rm_so; + unsigned len = regMatch.rm_eo - regMatch.rm_so; + result = + [[[NSString alloc] initWithBytes:base + length:len + encoding:NSUTF8StringEncoding] autorelease]; + } + return result; +} + +- (BOOL)matchesSubStringInString:(NSString *)str { + regmatch_t regMatch; + if ([self runRegexOnUTF8:[str UTF8String] + nmatch:1 + pmatch:®Match + flags:0]) { + // don't really care what matched, just report the match + return YES; + } + return NO; +} + - (NSEnumerator *)segmentEnumeratorForString:(NSString *)str { return [[[GTMRegexEnumerator alloc] initWithRegex:self processString:str @@ -266,8 +331,9 @@ static NSString *const kReplacementPattern = [GTMRegex regexWithPattern:kReplacementPattern options:kGTMRegexOptionSupressNewlineSupport]; #ifdef DEBUG - if (!replacementRegex) - NSLog(@"failed to parse out replacement regex!!!"); + if (!replacementRegex) { + _GTMDevLog(@"failed to parse out replacement regex!!!"); // COV_NF_LINE + } #endif GTMRegexEnumerator *relacementEnumerator = [[[GTMRegexEnumerator alloc] initWithRegex:replacementRegex @@ -292,8 +358,10 @@ static NSString *const kReplacementPattern = // pull them all into an array so we can walk this as many times as needed. replacements = [relacementEnumerator allObjects]; if (!replacements) { - NSLog(@"failed to create the replacements for subtituations"); + // COV_NF_START - no real way to force this in a unittest + _GTMDevLog(@"failed to create the replacements for substitutions"); return nil; + // COV_NF_END } } @@ -388,9 +456,11 @@ static NSString *const kReplacementPattern = if (execResult != 0) { #ifdef DEBUG if (execResult != REG_NOMATCH) { + // COV_NF_START - no real way to force this in a unittest NSString *errorStr = [self errorMessage:execResult]; - NSLog(@"%@: matching string \"%.20s...\", had error: \"%@\"", - self, utf8Str, errorStr); + _GTMDevLog(@"%@: matching string \"%.20s...\", had error: \"%@\"", + self, utf8Str, errorStr); + // COV_NF_END } #endif return NO; @@ -402,9 +472,8 @@ static NSString *const kReplacementPattern = @implementation GTMRegexEnumerator -- (id)init { - return [self initWithRegex:nil processString:nil allSegments:NO]; -} +// we don't block init because the class isn't exported, so no one can +// create one, or if they do, they get whatever happens... - (id)initWithRegex:(GTMRegex *)regex processString:(NSString *)str @@ -480,7 +549,7 @@ static NSString *const kReplacementPattern = size_t matchBufSize = ([regex_ subPatternCount] + 1) * sizeof(regmatch_t); nextMatches = malloc(matchBufSize); if (!nextMatches) - return nil; + return nil; // COV_NF_LINE - no real way to force this in a unittest // setup our range to work on nextMatches[0].rm_so = curParseIndex_; @@ -511,7 +580,7 @@ static NSString *const kReplacementPattern = savedRegMatches_ = nextMatches; nextMatches = malloc(matchBufSize); if (!nextMatches) - return nil; + return nil; // COV_NF_LINE - no real way to force this in a unittest isMatch = NO; // mark everything but the zero slot w/ not used @@ -568,14 +637,13 @@ static NSString *const kReplacementPattern = isMatch:isMatch] autorelease]; nextMatches = nil; } - } + } // COV_NF_START - no real way to force this in a test @catch (id e) { - NSLog(@"Exceptions while trying to advance enumeration (%@)", e); - } - - // if we still have something in our temp, free it - if (nextMatches) - free(nextMatches); + _GTMDevLog(@"Exceptions while trying to advance enumeration (%@)", e); + // if we still have something in our temp, free it + if (nextMatches) + free(nextMatches); + } // COV_NF_END return result; } @@ -593,10 +661,10 @@ static NSString *const kReplacementPattern = @implementation GTMRegexStringSegment - (id)init { - return [self initWithUTF8StrBuf:nil - regMatches:nil - numRegMatches:0 - isMatch:NO]; + // make sure init is never called, the class in in the header so someone + // could try to create it by mistake. + [self doesNotRecognizeSelector:_cmd]; + return nil; // COV_NF_LINE - return is just here to keep gcc happy } - (void)dealloc { @@ -669,8 +737,11 @@ static NSString *const kReplacementPattern = // check the args if (!utf8StrBuf_ || !regMatches_ || (numRegMatches_ < 0)) { + // COV_NF_START + // this could only happen something messed w/ our internal state. [self release]; return nil; + // COV_NF_END } return self; @@ -692,9 +763,12 @@ static NSString *const kReplacementPattern = - (NSString *)gtm_firstSubStringMatchedByPattern:(NSString *)pattern { GTMRegex *regex = [GTMRegex regexWithPattern:pattern]; - NSEnumerator *enumerator = [regex matchSegmentEnumeratorForString:self]; - GTMRegexStringSegment *firstMatch = [enumerator nextObject]; - return [firstMatch string]; + return [regex firstSubStringMatchedInString:self]; +} + +- (BOOL)gtm_subStringMatchesPattern:(NSString *)pattern { + GTMRegex *regex = [GTMRegex regexWithPattern:pattern]; + return [regex matchesSubStringInString:self]; } - (NSArray *)gtm_allSubstringsMatchedByPattern:(NSString *)pattern { -- cgit v1.2.3