1/* SOGoTest.m - this file is part of SOGo 2 * 3 * Copyright (C) 2010 Inverse inc. 4 * 5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> 6 * 7 * This file is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This file is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; see the file COPYING. If not, write to 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 */ 22 23#import <Foundation/NSDictionary.h> 24#import <Foundation/NSException.h> 25 26#import "SOGoTestRunner.h" 27 28#import "SOGoTest.h" 29 30static NSString *SOGoTestAssertException = @"SOGoTestAssertException"; 31 32/* Helper function for diffForString:andString */ 33static NSString *_stringForCharacterAtIndex(NSUInteger index, NSString *str, NSUInteger length) 34{ 35 NSString *chrStr; 36 unichar chr; 37 if (index < length) 38 { 39 chr = [str characterAtIndex: index]; 40 if (isprint(chr)) 41 { 42 chrStr = [NSString stringWithFormat: @"%c", chr]; 43 } 44 else 45 { 46 if (chr == 10) 47 chrStr = @"[NL]"; 48 else if (chr == 0) 49 chrStr = @"[\0]"; 50 else 51 chrStr = [NSString stringWithFormat: @"[NP: %u]", chr]; 52 } 53 } 54 else 55 { 56 chrStr = @"[none]"; 57 } 58 59 return chrStr; 60} 61 62@implementation SOGoTest 63 64+ (NSArray *) allTestClasses 65{ 66 NSMutableArray *allTestClasses; 67 NSArray *allSubClasses; 68 NSString *class; 69 int count, max; 70 71 allSubClasses = GSObjCAllSubclassesOfClass (self); 72 max = [allSubClasses count]; 73 allTestClasses = [NSMutableArray arrayWithCapacity: max]; 74 for (count = 0; count < max; count++) 75 { 76 class = NSStringFromClass ([allSubClasses objectAtIndex: count]); 77 if ([class hasPrefix: @"Test"]) 78 [allTestClasses addObject: class]; 79 } 80 81 return allTestClasses; 82} 83 84- (id) init 85{ 86 if ((self = [super init])) 87 { 88 testRunner = nil; 89 } 90 91 return self; 92} 93 94- (void) dealloc 95{ 96 [testRunner release]; 97 [super dealloc]; 98} 99 100- (void) setTestRunner: (SOGoTestRunner *) newTestRunner 101{ 102 ASSIGN (testRunner, newTestRunner); 103} 104 105- (void) setUp 106{ 107} 108 109- (void) tearDown 110{ 111} 112 113- (void) test: (BOOL) condition 114 message: (NSString *) message 115 file: (const char *) file 116 line: (int) line 117{ 118 NSDictionary *fileInfo; 119 120 if (!condition) 121 { 122 if (file) 123 fileInfo = [NSDictionary dictionaryWithObject: 124 [NSString stringWithFormat: @"%s:%d", file, line] 125 forKey: @"fileInfo"]; 126 else 127 fileInfo = nil; 128 [[NSException exceptionWithName: SOGoTestAssertException 129 reason: message 130 userInfo: fileInfo] raise]; 131 } 132} 133 134- (void) performTest: (SEL) testMethod 135{ 136 SOGoTestFailureCode failureCode; 137 138 failureCode = SOGoTestFailureSuccess; 139 NS_DURING 140 { 141 [self setUp]; 142 } 143 NS_HANDLER 144 { 145 failureCode = SOGoTestFailureError; 146 [testRunner reportException: localException 147 method: @"setUp" 148 withCode: failureCode]; 149 } 150 NS_ENDHANDLER; 151 152 if (failureCode == SOGoTestFailureSuccess) 153 { 154 NS_DURING 155 { 156 [self performSelector: testMethod]; 157 } 158 NS_HANDLER 159 { 160 if ([[localException name] 161 isEqualToString: SOGoTestAssertException]) 162 failureCode = SOGoTestFailureFailure; 163 else 164 failureCode = SOGoTestFailureError; 165 [testRunner reportException: localException 166 method: NSStringFromSelector (testMethod) 167 withCode: failureCode]; 168 } 169 NS_ENDHANDLER; 170 } 171 172 NS_DURING 173 { 174 [self tearDown]; 175 } 176 NS_HANDLER 177 { 178 failureCode = SOGoTestFailureError; 179 [testRunner reportException: localException 180 method: @"tearDown" 181 withCode: failureCode]; 182 } 183 NS_ENDHANDLER; 184 185 [testRunner incrementTestCounter: failureCode 186 afterMethod: NSStringFromSelector (testMethod)]; 187} 188 189- (BOOL) run 190{ 191 NSArray *methods; 192 NSString *method; 193 int count, max; 194 SEL testMethod; 195 196#if ((GNUSTEP_BASE_MAJOR_VERSION > 1) \ 197 || ((GNUSTEP_BASE_MAJOR_VERSION == 1) && (GNUSTEP_BASE_MINOR_VERSION >= 20))) 198 methods = GSObjCMethodNames (self, NO); 199#else 200 methods = GSObjCMethodNames (self); 201#endif 202 max = [methods count]; 203 for (count = 0; count < max; count++) 204 { 205 method = [methods objectAtIndex: count]; 206 if ([method hasPrefix: @"test"] 207 && [method rangeOfString: @":"].location == NSNotFound) 208 { 209 testMethod = NSSelectorFromString (method); 210 [self performTest: testMethod]; 211 } 212 } 213 214 return YES; 215} 216 217/* 218 Returns a string with a very verbose diff of the two strings. 219 In case the strings are equal it returns an empty string. 220 Example output for the strings 'flower' and 'flotera': 221 <begin of example> 2220 |f| 2231 |l| 2242 |o| 2253 |w|t|<-- 2264 |e| 2275 |r| 2286 |[none]|a|<-- 229 <end of example> 230*/ 231- (NSString*) stringFromDiffBetween: (NSString*) str1 232 and: (NSString*) str2 233{ 234 BOOL differencesFound = NO; 235 NSString *finalSTR = @""; 236 NSUInteger i, length1, length2; 237 NSString *sc1, *sc2; 238 239 length1 = [str1 length]; 240 length2 = [str2 length]; 241 for (i = 0; i < length1 || i < length2; i++) 242 { 243 sc1 = _stringForCharacterAtIndex(i, str1, length1); 244 sc2 = _stringForCharacterAtIndex(i, str2, length2); 245 246 if ([sc1 isEqualToString: sc2]) 247 finalSTR = [finalSTR stringByAppendingFormat: @"%lu |%@|\n", i, sc1]; 248 else 249 { 250 finalSTR = [finalSTR stringByAppendingFormat: @"%lu |%@|%@|<--\n", i, sc1, sc2]; 251 differencesFound = YES; 252 } 253 } 254 255 if (!differencesFound) 256 return @""; 257 258 return finalSTR; 259} 260 261 262@end 263