Skip to content

Commit

Permalink
Functions for running specs with custom spec runner classes; optional…
Browse files Browse the repository at this point in the history
… spec runner protocol delegate method called when specs start; beginnings of a view controller for displaying run status on the device or simulator; example of internal compiler error when using blocks in C++ files.
  • Loading branch information
Adam Milligan committed Jun 7, 2010
1 parent f6194b5 commit 7c1bef1
Show file tree
Hide file tree
Showing 15 changed files with 311 additions and 37 deletions.
52 changes: 49 additions & 3 deletions Cedar.xcodeproj/project.pbxproj
Expand Up @@ -8,6 +8,11 @@

/* Begin PBXBuildFile section */
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
AE16DC7B11BB514300270D0B /* CppSpecSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE16DC7A11BB514300270D0B /* CppSpecSpec.mm */; };
AE16DC9E11BB52B100270D0B /* ActualValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AE16DC9C11BB52B100270D0B /* ActualValue.h */; };
AE16DC9F11BB52B100270D0B /* ActualValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE16DC9D11BB52B100270D0B /* ActualValue.mm */; };
AE16DD3211BC874F00270D0B /* CDRExampleRunnerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = AE16DD3111BC874F00270D0B /* CDRExampleRunnerViewController.h */; };
AE16DD6B11BC93F600270D0B /* CDRExampleRunnerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AE16DD6A11BC93F600270D0B /* CDRExampleRunnerViewController.m */; };
AE603C7E118CC85100D312FC /* CDRDefaultRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = AE603C79118CC85100D312FC /* CDRDefaultRunner.m */; };
AE603C7F118CC85100D312FC /* CDRExample.m in Sources */ = {isa = PBXBuildFile; fileRef = AE603C7A118CC85100D312FC /* CDRExample.m */; };
AE603C80118CC85100D312FC /* CDRExampleBase.m in Sources */ = {isa = PBXBuildFile; fileRef = AE603C7B118CC85100D312FC /* CDRExampleBase.m */; };
Expand Down Expand Up @@ -72,6 +77,11 @@
089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8DC2EF5B0486A6940098B216 /* Cedar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cedar.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AE16DC7A11BB514300270D0B /* CppSpecSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CppSpecSpec.mm; sourceTree = "<group>"; };
AE16DC9C11BB52B100270D0B /* ActualValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActualValue.h; sourceTree = "<group>"; };
AE16DC9D11BB52B100270D0B /* ActualValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActualValue.mm; sourceTree = "<group>"; };
AE16DD3111BC874F00270D0B /* CDRExampleRunnerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDRExampleRunnerViewController.h; sourceTree = "<group>"; };
AE16DD6A11BC93F600270D0B /* CDRExampleRunnerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRExampleRunnerViewController.m; sourceTree = "<group>"; };
AE17ECE211B6F00B004C4DC0 /* MACROS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MACROS; sourceTree = "<group>"; };
AE4E524911B357F5001E36F3 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = "<group>"; };
AE603C79118CC85100D312FC /* CDRDefaultRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRDefaultRunner.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -168,24 +178,55 @@
name = Resources;
sourceTree = "<group>";
};
AE16DC9911BB524000270D0B /* Matchers */ = {
isa = PBXGroup;
children = (
AE16DC9C11BB52B100270D0B /* ActualValue.h */,
AE16DC9D11BB52B100270D0B /* ActualValue.mm */,
);
name = Matchers;
path = ../../cedar/Source/Matchers;
sourceTree = "<group>";
};
AE16DD2011BC868900270D0B /* iPhone */ = {
isa = PBXGroup;
children = (
AEBAB0C311B9D8120085EC6E /* CedarApplicationDelegate.m */,
AE16DD6A11BC93F600270D0B /* CDRExampleRunnerViewController.m */,
);
path = iPhone;
sourceTree = "<group>";
};
AE16DD2111BC868E00270D0B /* iPhone */ = {
isa = PBXGroup;
children = (
AEBAB0C111B9D2380085EC6E /* CedarApplicationDelegate.h */,
AE16DD3111BC874F00270D0B /* CDRExampleRunnerViewController.h */,
);
path = iPhone;
sourceTree = "<group>";
};
AE603C76118CC81500D312FC /* Source */ = {
isa = PBXGroup;
children = (
AE16DD2011BC868900270D0B /* iPhone */,
AE16DC9911BB524000270D0B /* Matchers */,
AE603C78118CC81D00D312FC /* Headers */,
AE603C79118CC85100D312FC /* CDRDefaultRunner.m */,
AE603C7A118CC85100D312FC /* CDRExample.m */,
AE603C7B118CC85100D312FC /* CDRExampleBase.m */,
AE603C7C118CC85100D312FC /* CDRExampleGroup.m */,
AE603C7D118CC85100D312FC /* CDRSpec.m */,
AE603CA9118CC94100D312FC /* Cedar.m */,
AEBAB0C311B9D8120085EC6E /* CedarApplicationDelegate.m */,
);
path = Source;
name = Source;
path = ../cedar/Source;
sourceTree = "<group>";
};
AE603C78118CC81D00D312FC /* Headers */ = {
isa = PBXGroup;
children = (
AE16DD2111BC868E00270D0B /* iPhone */,
AE603D69118CCB6000D312FC /* Cedar.h */,
AE603D6A118CCB6000D312FC /* CDRDefaultRunner.h */,
AE603D6B118CCB6000D312FC /* CDRExample.h */,
Expand All @@ -194,7 +235,6 @@
AE603D6E118CCB6000D312FC /* CDRExampleRunner.h */,
AE603D6F118CCB6000D312FC /* CDRSpec.h */,
AE603D70118CCB6000D312FC /* SpecHelper.h */,
AEBAB0C111B9D2380085EC6E /* CedarApplicationDelegate.h */,
);
path = Headers;
sourceTree = "<group>";
Expand All @@ -205,6 +245,7 @@
AE603D81118CCBBF00D312FC /* SpecSpec.m */,
AE603D82118CCBBF00D312FC /* SpecSpec2.m */,
AE603E14118CCE1F00D312FC /* main.m */,
AE16DC7A11BB514300270D0B /* CppSpecSpec.mm */,
);
path = Spec;
sourceTree = "<group>";
Expand All @@ -220,6 +261,7 @@
AE603D78118CCB6000D312FC /* SpecHelper.h in Headers */,
AED41F9411B871BC006DBB00 /* CDRSpec.h in Headers */,
AED41F9511B871C1006DBB00 /* CDRExampleBase.h in Headers */,
AE16DC9E11BB52B100270D0B /* ActualValue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -236,6 +278,7 @@
AED41F3E11B86A53006DBB00 /* CDRSpec.h in Headers */,
AED41F3F11B86A53006DBB00 /* SpecHelper.h in Headers */,
AEBAB0C211B9D2380085EC6E /* CedarApplicationDelegate.h in Headers */,
AE16DD3211BC874F00270D0B /* CDRExampleRunnerViewController.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -338,6 +381,7 @@
AE603C81118CC85100D312FC /* CDRExampleGroup.m in Sources */,
AE603C82118CC85100D312FC /* CDRSpec.m in Sources */,
AE603CAB118CC94100D312FC /* Cedar.m in Sources */,
AE16DC9F11BB52B100270D0B /* ActualValue.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -348,6 +392,7 @@
AE603DCA118CCCBE00D312FC /* SpecSpec.m in Sources */,
AE603DCB118CCCC700D312FC /* SpecSpec2.m in Sources */,
AE603E15118CCE1F00D312FC /* main.m in Sources */,
AE16DC7B11BB514300270D0B /* CppSpecSpec.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -362,6 +407,7 @@
AED41F3611B86A44006DBB00 /* CDRSpec.m in Sources */,
AED41F3711B86A44006DBB00 /* Cedar.m in Sources */,
AEBAB0C411B9D8120085EC6E /* CedarApplicationDelegate.m in Sources */,
AE16DD6B11BC93F600270D0B /* CDRExampleRunnerViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
1 change: 0 additions & 1 deletion Source/CDRSpec.m
Expand Up @@ -4,7 +4,6 @@
#import "CDRExampleRunner.h"

static CDRSpec *currentSpec;
extern CDRSpecBlock PENDING;

void describe(NSString *text, CDRSpecBlock block) {
CDRExampleGroup *parentGroup = currentSpec.currentGroup;
Expand Down
44 changes: 30 additions & 14 deletions Source/Cedar.m
Expand Up @@ -5,7 +5,7 @@
#import "CDRExampleRunner.h"
#import "CDRDefaultRunner.h"

BOOL isASpecClass(Class class) {
BOOL CDRIsASpecClass(Class class) {
if (strcmp("CDRSpec", class_getName(class))) {
while (class) {
if (class_conformsToProtocol(class, NSProtocolFromString(@"CDRSpec"))) {
Expand All @@ -14,44 +14,60 @@ BOOL isASpecClass(Class class) {
class = class_getSuperclass(class);
}
}

return NO;
}

NSArray *enumerateSpecClasses() {
NSArray *CDREnumerateSpecClasses() {
unsigned int numberOfClasses = objc_getClassList(NULL, 0);
Class classes[numberOfClasses];
numberOfClasses = objc_getClassList(classes, numberOfClasses);

NSMutableArray *specClasses = [NSMutableArray array];
for (unsigned int i = 0; i < numberOfClasses; ++i) {
Class class = classes[i];
if (isASpecClass(class)) {
if (CDRIsASpecClass(class)) {
[specClasses addObject:class];
}
}

return specClasses;
}

int runSpecs(NSArray *specClasses) {
id<CDRExampleRunner> runner = [[[CDRDefaultRunner alloc] init] autorelease];

NSArray *CDRCreateSpecsFromSpecClasses(NSArray *specClasses) {
NSMutableArray *specs = [[NSMutableArray alloc] initWithCapacity:[specClasses count]];
for (Class class in specClasses) {
CDRSpec *spec = [[class alloc] init];
[spec defineBehaviors];
[spec runWithRunner:runner];
[specs addObject:spec];
[spec release];
}

return specs;
}

int runSpecsWithCustomExampleRunner(NSArray *specClasses, id<CDRExampleRunner> runner) {
NSArray *specs = CDRCreateSpecsFromSpecClasses(specClasses);

if ([runner respondsToSelector:@selector(runWillStartWithSpecs:)]) {
[runner runWillStartWithSpecs:specs];
}

for (CDRSpec *spec in specs) {
[spec runWithRunner:runner];
}

[specs release];
return [runner result];
}

int runAllSpecs() {
return runAllSpecsWithCustomExampleRunner([[[CDRDefaultRunner alloc] init] autorelease]);
}

int runAllSpecsWithCustomExampleRunner(id<CDRExampleRunner> runner) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int result = runSpecs(enumerateSpecClasses());

int result = runSpecsWithCustomExampleRunner(CDREnumerateSpecClasses(), runner);

[pool drain];
return result;
}
11 changes: 0 additions & 11 deletions Source/CedarApplicationDelegate.m

This file was deleted.

4 changes: 4 additions & 0 deletions Source/Headers/CDRExampleRunner.h
Expand Up @@ -4,11 +4,15 @@

@protocol CDRExampleRunner <NSObject>

@required
- (void)exampleSucceeded:(CDRExample *)example;
- (void)example:(CDRExample *)example failedWithMessage:(NSString *)message;
- (void)example:(CDRExample *)example threwException:(NSException *)exception;
- (void)exampleThrewError:(CDRExample *)example;
- (void)examplePending:(CDRExample *)example;
- (int)result;

@optional
- (void)runWillStartWithSpecs:(NSArray *)specs;

@end
7 changes: 5 additions & 2 deletions Source/Headers/Cedar.h
@@ -1,4 +1,7 @@
#import <Foundation/Foundation.h>

int runSpecs(NSArray *specClasses);
int runAllSpecs();
@protocol CDRExampleRunner;

int runSpecsWithCustomExampleRunner(NSArray *specClasses, id<CDRExampleRunner> runner);
int runAllSpecs();
int runAllSpecsWithCustomExampleRunner(id<CDRExampleRunner> runner);
5 changes: 0 additions & 5 deletions Source/Headers/CedarApplicationDelegate.h

This file was deleted.

10 changes: 10 additions & 0 deletions Source/Headers/iPhone/CDRExampleRunnerViewController.h
@@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>
#import "CDRExampleRunner.h"
#import "CDRDefaultRunner.h"

@interface CDRExampleRunnerViewController : UITableViewController /*<CDRExampleRunner>*/ {
// TODO create a real runner here.
CDRDefaultRunner *stubRunner_;
}

@end
10 changes: 10 additions & 0 deletions Source/Headers/iPhone/CedarApplicationDelegate.h
@@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>

@class CDRExampleRunnerViewController;

@interface CedarApplicationDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window_;
CDRExampleRunnerViewController *viewController_;
}

@end
59 changes: 59 additions & 0 deletions Source/Matchers/ActualValue.h
@@ -0,0 +1,59 @@
#import <Foundation/Foundation.h>
#import "CDRExampleBase.h"

#include <iostream>
#include <sstream>

namespace Cedar {
namespace Matchers {

void fail(const NSString * failureMessage);

template<typename T>
class ActualValue {
private:
template<typename U>
ActualValue(const ActualValue<U> &);
template<typename U>
ActualValue & operator=(const ActualValue<U> &);

public:
ActualValue(const T &);

template<typename U>
void toEqual(const U &) const;

inline void foo(int i) const { std::cout << "int foo" << std::endl; }
inline void foo(NSObject * i) const { std::cout << "NSObject foo" << std::endl; };

template<typename U>
inline void bar(U i) const { std::cout << "template bar" << std::endl; }

private:
const T value_;
};

#pragma mark It's 2010 and linkers still can't handle templates in implementation files?

template<typename T>
const ActualValue<T> expect(const T & value) {
return ActualValue<T>(value);
}

template<typename T>
ActualValue<T>::ActualValue(const T & value) : value_(value) {
}

#pragma mark toEqual
template<typename T> template<typename U>
void ActualValue<T>::toEqual(const U & expectedValue) const {
if (expectedValue != value_) {
std::stringstream message;
message << "Expected <" << value_ << "> to equal <" << expectedValue << ">";

[[CDRSpecFailure specFailureWithReason:[NSString stringWithCString:message.str().c_str() encoding:NSUTF8StringEncoding]] raise];
}
}

}
}
11 changes: 11 additions & 0 deletions Source/Matchers/ActualValue.mm
@@ -0,0 +1,11 @@
#import "ActualValue.h"

namespace Cedar {
namespace Matchers {

void fail(const NSString *failureMessage) {
[[CDRSpecFailure specFailureWithReason:[NSString stringWithFormat:@"Failure: %@", failureMessage]] raise];
}

}
}

0 comments on commit 7c1bef1

Please sign in to comment.