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