/thirdparty/breakpad/common/mac/testing/GTMSenTestCase.m

http://github.com/tomahawk-player/tomahawk · Objective C · 366 lines · 279 code · 49 blank · 38 comment · 21 complexity · 17d553568e6f19f9586574109d29e26e MD5 · raw file

  1. //
  2. // GTMSenTestCase.m
  3. //
  4. // Copyright 2007-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 "GTMSenTestCase.h"
  19. #import <unistd.h>
  20. #if !GTM_IPHONE_SDK
  21. #import "GTMGarbageCollection.h"
  22. #endif // !GTM_IPHONE_SDK
  23. #if GTM_IPHONE_SDK
  24. #import <stdarg.h>
  25. @interface NSException (GTMSenTestPrivateAdditions)
  26. + (NSException *)failureInFile:(NSString *)filename
  27. atLine:(int)lineNumber
  28. reason:(NSString *)reason;
  29. @end
  30. @implementation NSException (GTMSenTestPrivateAdditions)
  31. + (NSException *)failureInFile:(NSString *)filename
  32. atLine:(int)lineNumber
  33. reason:(NSString *)reason {
  34. NSDictionary *userInfo =
  35. [NSDictionary dictionaryWithObjectsAndKeys:
  36. [NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey,
  37. filename, SenTestFilenameKey,
  38. nil];
  39. return [self exceptionWithName:SenTestFailureException
  40. reason:reason
  41. userInfo:userInfo];
  42. }
  43. @end
  44. @implementation NSException (GTMSenTestAdditions)
  45. + (NSException *)failureInFile:(NSString *)filename
  46. atLine:(int)lineNumber
  47. withDescription:(NSString *)formatString, ... {
  48. NSString *testDescription = @"";
  49. if (formatString) {
  50. va_list vl;
  51. va_start(vl, formatString);
  52. testDescription =
  53. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  54. va_end(vl);
  55. }
  56. NSString *reason = testDescription;
  57. return [self failureInFile:filename atLine:lineNumber reason:reason];
  58. }
  59. + (NSException *)failureInCondition:(NSString *)condition
  60. isTrue:(BOOL)isTrue
  61. inFile:(NSString *)filename
  62. atLine:(int)lineNumber
  63. withDescription:(NSString *)formatString, ... {
  64. NSString *testDescription = @"";
  65. if (formatString) {
  66. va_list vl;
  67. va_start(vl, formatString);
  68. testDescription =
  69. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  70. va_end(vl);
  71. }
  72. NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
  73. condition, isTrue ? "TRUE" : "FALSE", testDescription];
  74. return [self failureInFile:filename atLine:lineNumber reason:reason];
  75. }
  76. + (NSException *)failureInEqualityBetweenObject:(id)left
  77. andObject:(id)right
  78. inFile:(NSString *)filename
  79. atLine:(int)lineNumber
  80. withDescription:(NSString *)formatString, ... {
  81. NSString *testDescription = @"";
  82. if (formatString) {
  83. va_list vl;
  84. va_start(vl, formatString);
  85. testDescription =
  86. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  87. va_end(vl);
  88. }
  89. NSString *reason =
  90. [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
  91. [left description], [right description], testDescription];
  92. return [self failureInFile:filename atLine:lineNumber reason:reason];
  93. }
  94. + (NSException *)failureInEqualityBetweenValue:(NSValue *)left
  95. andValue:(NSValue *)right
  96. withAccuracy:(NSValue *)accuracy
  97. inFile:(NSString *)filename
  98. atLine:(int)lineNumber
  99. withDescription:(NSString *)formatString, ... {
  100. NSString *testDescription = @"";
  101. if (formatString) {
  102. va_list vl;
  103. va_start(vl, formatString);
  104. testDescription =
  105. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  106. va_end(vl);
  107. }
  108. NSString *reason;
  109. if (accuracy) {
  110. reason =
  111. [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
  112. left, right, testDescription];
  113. } else {
  114. reason =
  115. [NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@",
  116. left, right, accuracy, testDescription];
  117. }
  118. return [self failureInFile:filename atLine:lineNumber reason:reason];
  119. }
  120. + (NSException *)failureInRaise:(NSString *)expression
  121. inFile:(NSString *)filename
  122. atLine:(int)lineNumber
  123. withDescription:(NSString *)formatString, ... {
  124. NSString *testDescription = @"";
  125. if (formatString) {
  126. va_list vl;
  127. va_start(vl, formatString);
  128. testDescription =
  129. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  130. va_end(vl);
  131. }
  132. NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@",
  133. expression, testDescription];
  134. return [self failureInFile:filename atLine:lineNumber reason:reason];
  135. }
  136. + (NSException *)failureInRaise:(NSString *)expression
  137. exception:(NSException *)exception
  138. inFile:(NSString *)filename
  139. atLine:(int)lineNumber
  140. withDescription:(NSString *)formatString, ... {
  141. NSString *testDescription = @"";
  142. if (formatString) {
  143. va_list vl;
  144. va_start(vl, formatString);
  145. testDescription =
  146. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  147. va_end(vl);
  148. }
  149. NSString *reason;
  150. if ([[exception name] isEqualToString:SenTestFailureException]) {
  151. // it's our exception, assume it has the right description on it.
  152. reason = [exception reason];
  153. } else {
  154. // not one of our exception, use the exceptions reason and our description
  155. reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@",
  156. expression, [exception reason], testDescription];
  157. }
  158. return [self failureInFile:filename atLine:lineNumber reason:reason];
  159. }
  160. @end
  161. NSString *STComposeString(NSString *formatString, ...) {
  162. NSString *reason = @"";
  163. if (formatString) {
  164. va_list vl;
  165. va_start(vl, formatString);
  166. reason =
  167. [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
  168. va_end(vl);
  169. }
  170. return reason;
  171. }
  172. NSString *const SenTestFailureException = @"SenTestFailureException";
  173. NSString *const SenTestFilenameKey = @"SenTestFilenameKey";
  174. NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
  175. @interface SenTestCase (SenTestCasePrivate)
  176. // our method of logging errors
  177. + (void)printException:(NSException *)exception fromTestName:(NSString *)name;
  178. @end
  179. @implementation SenTestCase
  180. - (void)failWithException:(NSException*)exception {
  181. [exception raise];
  182. }
  183. - (void)setUp {
  184. }
  185. - (void)performTest:(SEL)sel {
  186. currentSelector_ = sel;
  187. @try {
  188. [self invokeTest];
  189. } @catch (NSException *exception) {
  190. [[self class] printException:exception
  191. fromTestName:NSStringFromSelector(sel)];
  192. [exception raise];
  193. }
  194. }
  195. + (void)printException:(NSException *)exception fromTestName:(NSString *)name {
  196. NSDictionary *userInfo = [exception userInfo];
  197. NSString *filename = [userInfo objectForKey:SenTestFilenameKey];
  198. NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey];
  199. NSString *className = NSStringFromClass([self class]);
  200. if ([filename length] == 0) {
  201. filename = @"Unknown.m";
  202. }
  203. fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n",
  204. [filename UTF8String],
  205. (long)[lineNumber integerValue],
  206. [className UTF8String],
  207. [name UTF8String],
  208. [[exception reason] UTF8String]);
  209. fflush(stderr);
  210. }
  211. - (void)invokeTest {
  212. NSException *e = nil;
  213. @try {
  214. // Wrap things in autorelease pools because they may
  215. // have an STMacro in their dealloc which may get called
  216. // when the pool is cleaned up
  217. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  218. // We don't log exceptions here, instead we let the person that called
  219. // this log the exception. This ensures they are only logged once but the
  220. // outer layers get the exceptions to report counts, etc.
  221. @try {
  222. [self setUp];
  223. @try {
  224. [self performSelector:currentSelector_];
  225. } @catch (NSException *exception) {
  226. e = [exception retain];
  227. }
  228. [self tearDown];
  229. } @catch (NSException *exception) {
  230. e = [exception retain];
  231. }
  232. [pool release];
  233. } @catch (NSException *exception) {
  234. e = [exception retain];
  235. }
  236. if (e) {
  237. [e autorelease];
  238. [e raise];
  239. }
  240. }
  241. - (void)tearDown {
  242. }
  243. - (NSString *)description {
  244. // This matches the description OCUnit would return to you
  245. return [NSString stringWithFormat:@"-[%@ %@]", [self class],
  246. NSStringFromSelector(currentSelector_)];
  247. }
  248. @end
  249. #endif // GTM_IPHONE_SDK
  250. @implementation GTMTestCase : SenTestCase
  251. - (void)invokeTest {
  252. Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");
  253. if (devLogClass) {
  254. [devLogClass performSelector:@selector(enableTracking)];
  255. [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
  256. }
  257. [super invokeTest];
  258. if (devLogClass) {
  259. [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
  260. [devLogClass performSelector:@selector(disableTracking)];
  261. }
  262. }
  263. @end
  264. // Leak detection
  265. #if !GTM_IPHONE_DEVICE
  266. // Don't want to get leaks on the iPhone Device as the device doesn't
  267. // have 'leaks'. The simulator does though.
  268. // COV_NF_START
  269. // We don't have leak checking on by default, so this won't be hit.
  270. static void _GTMRunLeaks(void) {
  271. // This is an atexit handler. It runs leaks for us to check if we are
  272. // leaking anything in our tests.
  273. const char* cExclusionsEnv = getenv("GTM_LEAKS_SYMBOLS_TO_IGNORE");
  274. NSMutableString *exclusions = [NSMutableString string];
  275. if (cExclusionsEnv) {
  276. NSString *exclusionsEnv = [NSString stringWithUTF8String:cExclusionsEnv];
  277. NSArray *exclusionsArray = [exclusionsEnv componentsSeparatedByString:@","];
  278. NSString *exclusion;
  279. NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet];
  280. GTM_FOREACH_OBJECT(exclusion, exclusionsArray) {
  281. exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet];
  282. [exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
  283. }
  284. }
  285. NSString *string
  286. = [NSString stringWithFormat:@"/usr/bin/leaks %@%d"
  287. @"| /usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
  288. exclusions, getpid()];
  289. int ret = system([string UTF8String]);
  290. if (ret) {
  291. fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d",
  292. __FILE__, __LINE__, ret);
  293. fflush(stderr);
  294. }
  295. }
  296. // COV_NF_END
  297. static __attribute__((constructor)) void _GTMInstallLeaks(void) {
  298. BOOL checkLeaks = YES;
  299. #if !GTM_IPHONE_SDK
  300. checkLeaks = GTMIsGarbageCollectionEnabled() ? NO : YES;
  301. #endif // !GTM_IPHONE_SDK
  302. if (checkLeaks) {
  303. checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO;
  304. if (checkLeaks) {
  305. // COV_NF_START
  306. // We don't have leak checking on by default, so this won't be hit.
  307. fprintf(stderr, "Leak Checking Enabled\n");
  308. fflush(stderr);
  309. int ret = atexit(&_GTMRunLeaks);
  310. _GTMDevAssert(ret == 0,
  311. @"Unable to install _GTMRunLeaks as an atexit handler (%d)",
  312. errno);
  313. // COV_NF_END
  314. }
  315. }
  316. }
  317. #endif // !GTM_IPHONE_DEVICE