PageRenderTime 30ms CodeModel.GetById 7ms RepoModel.GetById 3ms app.codeStats 0ms

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