main
  1//
  2// Licensed under the terms in License.txt
  3//
  4// Copyright 2010 Allen Ding. All rights reserved.
  5//
  6
  7#import "KWSpec.h"
  8#import <objc/runtime.h>
  9#import "KWExample.h"
 10#import "KWExampleGroupBuilder.h"
 11#import "KWIntercept.h"
 12#import "KWObjCUtilities.h"
 13#import "KWStringUtilities.h"
 14#import "NSMethodSignature+KiwiAdditions.h"
 15#import "KWFailure.h"
 16#import "KWExampleSuite.h"
 17
 18
 19@interface KWSpec()
 20
 21#pragma mark -
 22#pragma mark Properties
 23
 24@property (nonatomic, retain) KWExample *example;
 25
 26@end
 27
 28@implementation KWSpec
 29
 30@synthesize example;
 31
 32- (void)dealloc 
 33{
 34    [example release];
 35    [super dealloc];
 36}
 37
 38/* This method is only implemented by sub-classes */
 39
 40+ (void)buildExampleGroups {}
 41
 42/* Reported by XCode SenTestingKit Runner before and after invocation of the test
 43   Use camel case to make method friendly names from example description
 44 */
 45
 46- (NSString *)description
 47{
 48    KWExample *currentExample = self.example ? self.example : [[self invocation] kw_example];
 49    NSString *name = [currentExample descriptionWithContext];
 50    
 51    // CamelCase the string
 52    NSArray *words = [name componentsSeparatedByString:@" "];
 53    name = @"";
 54    for (NSString *word in words) {
 55        if ([word length] < 1)
 56        {
 57            continue;
 58        }
 59        name = [name stringByAppendingString:[[word substringToIndex:1] uppercaseString]];
 60        name = [name stringByAppendingString:[word substringFromIndex:1]];
 61    }
 62    
 63    // Replace the commas with underscores to separate the levels of context
 64    name = [name stringByReplacingOccurrencesOfString:@"," withString:@"_"];
 65    
 66    // Strip out characters not legal in function names
 67    NSError *error = nil;
 68    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-zA-Z0-9_]*" options:0 error:&error];
 69    name = [regex stringByReplacingMatchesInString:name options:0 range:NSMakeRange(0, name.length) withTemplate:@""];
 70
 71    return [NSString stringWithFormat:@"-[%@ %@]", NSStringFromClass([self class]), name];
 72}
 73
 74#pragma mark -
 75#pragma mark Getting Invocations
 76
 77/* Called by the SenTestingKit test suite to get an array of invocations that
 78   should be run on instances of test cases. */
 79
 80+ (NSArray *)testInvocations 
 81{
 82    SEL selector = @selector(buildExampleGroups);
 83
 84    // Only return invocation if the receiver is a concrete spec that has overridden -buildExampleGroups.
 85    if ([self methodForSelector:selector] == [KWSpec methodForSelector:selector])
 86        return nil;
 87
 88    KWExampleSuite *exampleSuite = [[KWExampleGroupBuilder sharedExampleGroupBuilder] buildExampleGroups:^{
 89        [self buildExampleGroups];
 90    }];
 91  
 92    return [exampleSuite invocationsForTestCase];
 93}
 94
 95#pragma mark -
 96#pragma mark Running Specs
 97
 98- (void)invokeTest 
 99{
100    self.example = [[self invocation] kw_example];
101
102    NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
103
104    @try {
105        [self.example runWithDelegate:self];
106    } @catch (NSException *exception) {
107        [self failWithException:exception];
108    }
109    
110    [[self invocation] kw_setExample:nil];
111    
112    [subPool release];
113}
114
115#pragma mark - KWExampleGroupDelegate methods
116
117- (void)example:(KWExample *)example didFailWithFailure:(KWFailure *)failure
118{
119    [self failWithException:[failure exceptionValue]];
120}
121
122#pragma mark -
123#pragma mark Verification proxies
124
125+ (id)addVerifier:(id<KWVerifying>)aVerifier
126{
127  return [[[KWExampleGroupBuilder sharedExampleGroupBuilder] currentExample] addVerifier:aVerifier];
128}
129
130+ (id)addExistVerifierWithExpectationType:(KWExpectationType)anExpectationType callSite:(KWCallSite *)aCallSite
131{
132  return [[[KWExampleGroupBuilder sharedExampleGroupBuilder] currentExample] addExistVerifierWithExpectationType:anExpectationType callSite:aCallSite];
133}
134
135+ (id)addMatchVerifierWithExpectationType:(KWExpectationType)anExpectationType callSite:(KWCallSite *)aCallSite
136{
137  return [[[KWExampleGroupBuilder sharedExampleGroupBuilder] currentExample] addMatchVerifierWithExpectationType:anExpectationType callSite:aCallSite];
138}
139
140+ (id)addAsyncVerifierWithExpectationType:(KWExpectationType)anExpectationType callSite:(KWCallSite *)aCallSite timeout:(NSInteger)timeout
141{
142  return [[[KWExampleGroupBuilder sharedExampleGroupBuilder] currentExample] addAsyncVerifierWithExpectationType:anExpectationType callSite:aCallSite timeout:timeout];
143}
144
145@end