PageRenderTime 67ms CodeModel.GetById 1ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 1ms

/core/externals/google-toolbox-for-mac/UnitTesting/GTMUnitTestDevLog.m

http://macfuse.googlecode.com/
Objective C | 298 lines | 225 code | 36 blank | 37 comment | 17 complexity | f45208ac39423b7f420637d21b06de58 MD5 | raw file
  1//
  2//  GTMUnitTestDevLog.m
  3//
  4//  Copyright 2008 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMUnitTestDevLog.h"
 20
 21
 22#import "GTMRegex.h"
 23#import "GTMSenTestCase.h"
 24
 25#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
 26// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
 27// -Wmissing-format-attribute
 28// when the function is anything more complex than foo(NSString *fmt, ...).
 29// You see the error inside the function when you turn ... into va_args and
 30// attempt to call another function (like vsprintf for example).
 31// So we just shut off the warning for this file. We reenable it at the end.
 32#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
 33#endif  // !__clang__
 34
 35#if !GTM_IPHONE_SDK
 36// Add support for grabbing messages from Carbon.
 37#import <CoreServices/CoreServices.h>
 38static void GTMDevLogDebugAssert(OSType componentSignature,
 39                                 UInt32 options,
 40                                 const char *assertionString,
 41                                 const char *exceptionLabelString,
 42                                 const char *errorString,
 43                                 const char *fileName,
 44                                 long lineNumber,
 45                                 void *value,
 46                                 ConstStr255Param outputMsg) {
 47  NSString *outLog = [[[NSString alloc] initWithBytes:&(outputMsg[1])
 48                                               length:StrLength(outputMsg)
 49                                             encoding:NSMacOSRomanStringEncoding]
 50                      autorelease];
 51  _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
 52}
 53static inline void GTMInstallDebugAssertOutputHandler(void) {
 54  InstallDebugAssertOutputHandler(GTMDevLogDebugAssert);
 55}
 56static inline void GTMUninstallDebugAssertOutputHandler(void) {
 57  InstallDebugAssertOutputHandler(NULL);
 58}
 59#else  // GTM_IPHONE_SDK
 60static inline void GTMInstallDebugAssertOutputHandler(void) {};
 61static inline void GTMUninstallDebugAssertOutputHandler(void) {};
 62#endif  // GTM_IPHONE_SDK
 63
 64@interface GTMUnttestDevLogAssertionHandler : NSAssertionHandler
 65@end
 66
 67@implementation GTMUnttestDevLogAssertionHandler
 68- (void)handleFailureInMethod:(SEL)selector
 69                       object:(id)object
 70                         file:(NSString *)fileName
 71                   lineNumber:(NSInteger)line
 72                  description:(NSString *)format, ... {
 73  va_list argList;
 74  va_start(argList, format);
 75  NSString *descStr
 76    = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
 77  va_end(argList);
 78
 79  // You need a format that will be useful in logs, but won't trip up Xcode or
 80  // any other build systems parsing of the output.
 81  NSString *outLog
 82    = [NSString stringWithFormat:@"RecordedNSAssert in %@ - %@ (%@:%ld)",
 83                                 NSStringFromSelector(selector),
 84                                 descStr,
 85                                 fileName, (long)line];
 86  // To avoid unused variable warning when _GTMDevLog is stripped.
 87  (void)outLog;
 88  _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
 89  [NSException raise:NSInternalInconsistencyException
 90              format:@"NSAssert raised"];
 91}
 92
 93- (void)handleFailureInFunction:(NSString *)functionName
 94                           file:(NSString *)fileName
 95                     lineNumber:(NSInteger)line
 96                    description:(NSString *)format, ... {
 97  va_list argList;
 98  va_start(argList, format);
 99  NSString *descStr
100    = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
101  va_end(argList);
102
103  // You need a format that will be useful in logs, but won't trip up Xcode or
104  // any other build systems parsing of the output.
105  NSString *outLog
106    = [NSString stringWithFormat:@"RecordedNSAssert in %@ - %@ (%@:%ld)",
107                                 functionName,
108                                 descStr,
109                                 fileName, (long)line];
110  // To avoid unused variable warning when _GTMDevLog is stripped.
111  (void)outLog;
112  _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
113  [NSException raise:NSInternalInconsistencyException
114              format:@"NSAssert raised"];
115}
116
117@end
118
119@implementation GTMUnitTestDevLog
120// If unittests are ever being run on separate threads, this may need to be
121// made a thread local variable.
122static BOOL gTrackingEnabled = NO;
123
124+ (NSMutableArray *)patterns {
125  static NSMutableArray *patterns = nil;
126  if (!patterns) {
127    patterns = [[NSMutableArray array] retain];
128  }
129  return patterns;
130}
131
132+ (BOOL)isTrackingEnabled {
133  return gTrackingEnabled;
134}
135
136+ (void)enableTracking {
137  GTMInstallDebugAssertOutputHandler();
138
139  NSMutableDictionary *threadDictionary
140    = [[NSThread currentThread] threadDictionary];
141  if ([threadDictionary objectForKey:@"NSAssertionHandler"] != nil) {
142    NSLog(@"Warning: replacing NSAssertionHandler to capture assertions");
143  }
144
145  // Install an assertion handler to capture those.
146  GTMUnttestDevLogAssertionHandler *handler =
147    [[[GTMUnttestDevLogAssertionHandler alloc] init] autorelease];
148  [threadDictionary setObject:handler forKey:@"NSAssertionHandler"];
149
150  gTrackingEnabled = YES;
151}
152
153+ (void)disableTracking {
154  GTMUninstallDebugAssertOutputHandler();
155
156  // Clear our assertion handler back out.
157  NSMutableDictionary *threadDictionary
158    = [[NSThread currentThread] threadDictionary];
159  [threadDictionary removeObjectForKey:@"NSAssertionHandler"];
160
161  gTrackingEnabled = NO;
162}
163
164+ (void)log:(NSString*)format, ... {
165  va_list argList;
166  va_start(argList, format);
167  [self log:format args:argList];
168  va_end(argList);
169}
170
171+ (void)log:(NSString*)format args:(va_list)args {
172  if ([self isTrackingEnabled]) {
173    NSString *logString = [[[NSString alloc] initWithFormat:format
174                                                  arguments:args] autorelease];
175    @synchronized(self) {
176      NSMutableArray *patterns = [self patterns];
177      BOOL logError = [patterns count] == 0 ? YES : NO;
178      GTMRegex *regex = nil;
179      if (!logError) {
180        regex = [[[patterns objectAtIndex:0] retain] autorelease];
181        logError = [regex matchesString:logString] ? NO : YES;
182        [patterns removeObjectAtIndex:0];
183      }
184      if (logError) {
185        if (regex) {
186          [NSException raise:SenTestFailureException
187                      format:@"Unexpected log: %@\nExpected: %@",
188           logString, regex];
189        } else {
190          [NSException raise:SenTestFailureException
191                      format:@"Unexpected log: %@", logString];
192        }
193      } else {
194        static BOOL envChecked = NO;
195        static BOOL showExpectedLogs = YES;
196        if (!envChecked) {
197          showExpectedLogs = getenv("GTM_SHOW_UNITTEST_DEVLOGS") ? YES : NO;
198        }
199        if (showExpectedLogs) {
200          NSLog(@"Expected Log: %@", logString);
201        }
202      }
203    }
204  } else {
205    NSLogv(format, args);
206  }
207}
208
209+ (void)expectString:(NSString *)format, ... {
210  va_list argList;
211  va_start(argList, format);
212  NSString *string = [[[NSString alloc] initWithFormat:format
213                                             arguments:argList] autorelease];
214  va_end(argList);
215  NSString *pattern = [GTMRegex escapedPatternForString:string];
216  [self expect:1 casesOfPattern:@"%@", pattern];
217
218}
219
220+ (void)expectPattern:(NSString *)format, ... {
221  va_list argList;
222  va_start(argList, format);
223  [self expect:1 casesOfPattern:format args:argList];
224  va_end(argList);
225}
226
227+ (void)expect:(NSUInteger)n casesOfString:(NSString *)format, ... {
228  va_list argList;
229  va_start(argList, format);
230  NSString *string = [[[NSString alloc] initWithFormat:format
231                                             arguments:argList] autorelease];
232  va_end(argList);
233  NSString *pattern = [GTMRegex escapedPatternForString:string];
234  [self expect:n casesOfPattern:@"%@", pattern];
235}
236
237+ (void)expect:(NSUInteger)n casesOfPattern:(NSString*)format, ... {
238  va_list argList;
239  va_start(argList, format);
240  [self expect:n casesOfPattern:format args:argList];
241  va_end(argList);
242}
243
244+ (void)expect:(NSUInteger)n
245casesOfPattern:(NSString*)format
246          args:(va_list)args {
247  NSString *pattern = [[[NSString alloc] initWithFormat:format
248                                              arguments:args] autorelease];
249  GTMRegex *regex = [GTMRegex regexWithPattern:pattern
250                                       options:kGTMRegexOptionSupressNewlineSupport];
251  @synchronized(self) {
252    NSMutableArray *patterns = [self patterns];
253    for (NSUInteger i = 0; i < n; ++i) {
254      [patterns addObject:regex];
255    }
256  }
257}
258
259+ (void)verifyNoMoreLogsExpected {
260  @synchronized(self) {
261    NSMutableArray *patterns = [self patterns];
262    if ([patterns count] > 0) {
263      NSMutableArray *patternsCopy = [[patterns copy] autorelease];
264      [self resetExpectedLogs];
265      [NSException raise:SenTestFailureException
266                  format:@"Logs still expected %@", patternsCopy];
267    }
268  }
269}
270
271+ (void)resetExpectedLogs {
272  @synchronized(self) {
273    NSMutableArray *patterns = [self patterns];
274    [patterns removeAllObjects];
275  }
276}
277@end
278
279
280@implementation GTMUnitTestDevLogDebug
281
282+ (void)expect:(NSUInteger)n
283casesOfPattern:(NSString*)format
284          args:(va_list)args {
285#if DEBUG
286  // In debug, let the base work happen
287  [super expect:n casesOfPattern:format args:args];
288#else
289  // nothing when not in debug
290#endif
291}
292
293@end
294
295#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
296// See comment at top of file.
297#pragma GCC diagnostic error "-Wmissing-format-attribute"
298#endif  // !__clang__