Permalink
Browse files

shared examples support. closes #4

  • Loading branch information...
1 parent 433a0df commit 2aa3cd9d6fcd126949ab7879a16570e2056c6042 @petejkim petejkim committed Jun 2, 2012
View
@@ -45,9 +45,24 @@ Standard OCUnit matchers such as `STAssertEqualObjects` and `STAssertNil` work,
```objective-c
#import "Specta.h"
+SharedExamplesBegin(MySharedExamples)
+// Global shared examples are shared across all spec files.
+
+sharedExamplesFor(@"a shared behavior", ^(NSDictionary *data) {
+ it(@"should do some stuff", ^{
+ // ...
+ });
+});
+
+SharedExamplesEnd
+
SpecBegin(Thing)
describe(@"Thing", ^{
+ sharedExamplesFor(@"another shared behavior", ^(NSDictionary *data) {
+ // Locally defined shared examples can override global shared examples within its scope.
+ });
+
beforeAll(^{
// This is run once and only once before all of the examples
// in this group and before any beforeEach blocks.
@@ -65,6 +80,8 @@ describe(@"Thing", ^{
// ...
});
+ itShouldBehaveLike(@"a shared behavior", [NSDictionary dictionaryWithObjectsAndKeys:@"obj", @"key", nil]);
+
describe(@"Nested examples", ^{
it(@"should do even more stuff", ^{
// ...
@@ -93,6 +110,7 @@ SpecEnd
* `beforeEach` and `afterEach` are also aliased as `before` and `after` respectively.
* `describe` is also aliased as `context`.
* `it` is also aliased as `example` and `specify`.
+* `itShouldBehaveLike` is also aliased as `itBehavesLike`.
* Use `pending` or prepend `x` to `describe`, `context`, `example, `it`, and `specify` to mark examples or groups as pending.
* Do `#define SPT_CEDAR_SYNTAX` if you prefer to write `SPEC_BEGIN` and `SPEC_END` instead of `SpecBegin` and `SpecEnd`.
@@ -103,10 +121,6 @@ Refer to
on how to run specs from command line or in continuous integration
servers.
-### FEATURES COMING SOON
-
-* Shared Examples
-
### CONTRIBUTION GUIDELINES
* Please use only spaces and indent 2 spaces at a time.
@@ -66,6 +66,16 @@
E9B777FD14BA329400D8DC76 /* SPTExampleGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = E9D9420914B8B42A00CD833A /* SPTExampleGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
E9B777FE14BA329400D8DC76 /* SPTSenTestCase.h in Headers */ = {isa = PBXBuildFile; fileRef = E9B7777F14B9E15300D8DC76 /* SPTSenTestCase.h */; settings = {ATTRIBUTES = (Public, ); }; };
E9BDBAB914BE2F3A00102FB5 /* MiscTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E9BDBAB814BE2F3A00102FB5 /* MiscTest.m */; };
+ E9D3DED6157A385C0054978E /* SharedExamplesTest1.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DED5157A385C0054978E /* SharedExamplesTest1.m */; };
+ E9D3DED7157A385C0054978E /* SharedExamplesTest1.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DED5157A385C0054978E /* SharedExamplesTest1.m */; };
+ E9D3DEDA157A3F3D0054978E /* SPTSharedExampleGroups.h in Headers */ = {isa = PBXBuildFile; fileRef = E9D3DED9157A3F340054978E /* SPTSharedExampleGroups.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ E9D3DEDB157A3F3D0054978E /* SPTSharedExampleGroups.h in Headers */ = {isa = PBXBuildFile; fileRef = E9D3DED9157A3F340054978E /* SPTSharedExampleGroups.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ E9D3DEDD157A3F470054978E /* SPTSharedExampleGroups.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEDC157A3F470054978E /* SPTSharedExampleGroups.m */; };
+ E9D3DEDE157A3F470054978E /* SPTSharedExampleGroups.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEDC157A3F470054978E /* SPTSharedExampleGroups.m */; };
+ E9D3DEE0157A45550054978E /* SharedExamplesTest2.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEDF157A45540054978E /* SharedExamplesTest2.m */; };
+ E9D3DEE1157A45550054978E /* SharedExamplesTest2.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEDF157A45540054978E /* SharedExamplesTest2.m */; };
+ E9D3DEE3157A55F50054978E /* SharedExamplesTest3.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEE2157A55F40054978E /* SharedExamplesTest3.m */; };
+ E9D3DEE4157A55F50054978E /* SharedExamplesTest3.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D3DEE2157A55F40054978E /* SharedExamplesTest3.m */; };
E9D9420E14B8B42A00CD833A /* Specta-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = E9D9420414B8B42A00CD833A /* Specta-Prefix.pch */; settings = {ATTRIBUTES = (Public, ); }; };
E9D9420F14B8B42A00CD833A /* Specta.h in Headers */ = {isa = PBXBuildFile; fileRef = E9D9420514B8B42A00CD833A /* Specta.h */; settings = {ATTRIBUTES = (Public, ); }; };
E9D9421014B8B42A00CD833A /* Specta.m in Sources */ = {isa = PBXBuildFile; fileRef = E9D9420614B8B42A00CD833A /* Specta.m */; };
@@ -134,6 +144,11 @@
E9B777B314BA294C00D8DC76 /* Specta-iOSTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Specta-iOSTests.octest"; sourceTree = BUILT_PRODUCTS_DIR; };
E9B777DE14BA30F600D8DC76 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
E9BDBAB814BE2F3A00102FB5 /* MiscTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MiscTest.m; sourceTree = "<group>"; };
+ E9D3DED5157A385C0054978E /* SharedExamplesTest1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharedExamplesTest1.m; sourceTree = "<group>"; };
+ E9D3DED9157A3F340054978E /* SPTSharedExampleGroups.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTSharedExampleGroups.h; sourceTree = "<group>"; };
+ E9D3DEDC157A3F470054978E /* SPTSharedExampleGroups.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTSharedExampleGroups.m; sourceTree = "<group>"; };
+ E9D3DEDF157A45540054978E /* SharedExamplesTest2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharedExamplesTest2.m; sourceTree = "<group>"; };
+ E9D3DEE2157A55F40054978E /* SharedExamplesTest3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharedExamplesTest3.m; sourceTree = "<group>"; };
E9D9420414B8B42A00CD833A /* Specta-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Specta-Prefix.pch"; sourceTree = "<group>"; };
E9D9420514B8B42A00CD833A /* Specta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Specta.h; sourceTree = "<group>"; };
E9D9420614B8B42A00CD833A /* Specta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Specta.m; sourceTree = "<group>"; };
@@ -266,6 +281,8 @@
E9D9420814B8B42A00CD833A /* SPTExample.m */,
E9D9420914B8B42A00CD833A /* SPTExampleGroup.h */,
E9D9420A14B8B42A00CD833A /* SPTExampleGroup.m */,
+ E9D3DED9157A3F340054978E /* SPTSharedExampleGroups.h */,
+ E9D3DEDC157A3F470054978E /* SPTSharedExampleGroups.m */,
E9B7777F14B9E15300D8DC76 /* SPTSenTestCase.h */,
E9B7778114B9E15A00D8DC76 /* SPTSenTestCase.m */,
E944CA2814C4B5E300821DED /* SPTSenTestInvocation.h */,
@@ -299,6 +316,9 @@
E910177414B9114A0087CD46 /* FailingSpecTest.m */,
E9A204C814C79F81006E4A66 /* PendingSpecTest1.m */,
E9A204CC14C7A487006E4A66 /* PendingSpecTest2.m */,
+ E9D3DED5157A385C0054978E /* SharedExamplesTest1.m */,
+ E9D3DEDF157A45540054978E /* SharedExamplesTest2.m */,
+ E9D3DEE2157A55F40054978E /* SharedExamplesTest3.m */,
E96187B114C4AC690021D7CE /* UnexpectedExceptionTest.m */,
E9BDBAB814BE2F3A00102FB5 /* MiscTest.m */,
E9D96A2814B6B8AB007D9521 /* frameworks */,
@@ -411,6 +431,7 @@
E9B777FB14BA329400D8DC76 /* SPTSpec.h in Headers */,
E9B777FC14BA329400D8DC76 /* SPTExample.h in Headers */,
E9B777FD14BA329400D8DC76 /* SPTExampleGroup.h in Headers */,
+ E9D3DEDB157A3F3D0054978E /* SPTSharedExampleGroups.h in Headers */,
E9B777FE14BA329400D8DC76 /* SPTSenTestCase.h in Headers */,
E944CA2A14C4B5E300821DED /* SPTSenTestInvocation.h in Headers */,
E944CA3014C4B70000821DED /* SpectaTypes.h in Headers */,
@@ -426,6 +447,7 @@
E9D9420E14B8B42A00CD833A /* Specta-Prefix.pch in Headers */,
E9D9421114B8B42A00CD833A /* SPTExample.h in Headers */,
E9D9421314B8B42A00CD833A /* SPTExampleGroup.h in Headers */,
+ E9D3DEDA157A3F3D0054978E /* SPTSharedExampleGroups.h in Headers */,
E9D9421614B8B42A00CD833A /* SPTSpec.h in Headers */,
E9B7778014B9E15300D8DC76 /* SPTSenTestCase.h in Headers */,
E944CA2914C4B5E300821DED /* SPTSenTestInvocation.h in Headers */,
@@ -596,6 +618,7 @@
E9B777D814BA308B00D8DC76 /* SPTExampleGroup.m in Sources */,
E9B777D914BA308B00D8DC76 /* SPTSenTestCase.m in Sources */,
E944CA2D14C4B5F600821DED /* SPTSenTestInvocation.m in Sources */,
+ E9D3DEDE157A3F470054978E /* SPTSharedExampleGroups.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -625,6 +648,9 @@
E96187C714C4AFA70021D7CE /* MiscTest.m in Sources */,
E9A204CA14C79F81006E4A66 /* PendingSpecTest1.m in Sources */,
E9A204CE14C7A487006E4A66 /* PendingSpecTest2.m in Sources */,
+ E9D3DED7157A385C0054978E /* SharedExamplesTest1.m in Sources */,
+ E9D3DEE1157A45550054978E /* SharedExamplesTest2.m in Sources */,
+ E9D3DEE4157A55F50054978E /* SharedExamplesTest3.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -638,6 +664,7 @@
E9D9421414B8B42A00CD833A /* SPTExampleGroup.m in Sources */,
E9B7778214B9E15A00D8DC76 /* SPTSenTestCase.m in Sources */,
E944CA2C14C4B5F600821DED /* SPTSenTestInvocation.m in Sources */,
+ E9D3DEDD157A3F470054978E /* SPTSharedExampleGroups.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -667,6 +694,9 @@
E96187B214C4AC690021D7CE /* UnexpectedExceptionTest.m in Sources */,
E9A204C914C79F81006E4A66 /* PendingSpecTest1.m in Sources */,
E9A204CD14C7A487006E4A66 /* PendingSpecTest2.m in Sources */,
+ E9D3DED6157A385C0054978E /* SharedExamplesTest1.m in Sources */,
+ E9D3DEE0157A45550054978E /* SharedExamplesTest2.m in Sources */,
+ E9D3DEE3157A55F50054978E /* SharedExamplesTest3.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
@@ -14,6 +14,7 @@
NSMutableArray *_afterAllArray;
NSMutableArray *_beforeEachArray;
NSMutableArray *_afterEachArray;
+ NSMutableDictionary *_sharedExamples;
unsigned int _exampleCount;
unsigned int _ranExampleCount;
}
@@ -26,6 +27,7 @@
@property (nonatomic, retain) NSMutableArray *afterAllArray;
@property (nonatomic, retain) NSMutableArray *beforeEachArray;
@property (nonatomic, retain) NSMutableArray *afterEachArray;
+@property (nonatomic, retain) NSMutableDictionary *sharedExamples;
@property (nonatomic) unsigned int exampleCount;
@property (nonatomic) unsigned int ranExampleCount;
View
@@ -22,6 +22,7 @@ @implementation SPTExampleGroup
, afterAllArray=_afterAllArray
, beforeEachArray=_beforeEachArray
, afterEachArray=_afterEachArray
+, sharedExamples=_sharedExamples
, exampleCount=_exampleCount
, ranExampleCount=_ranExampleCount
;
@@ -35,6 +36,7 @@ - (void)dealloc {
self.afterAllArray = nil;
self.beforeEachArray = nil;
self.afterEachArray = nil;
+ self.sharedExamples = nil;
[super dealloc];
}
@@ -49,6 +51,7 @@ - (id)init {
self.afterAllArray = [NSMutableArray array];
self.beforeEachArray = [NSMutableArray array];
self.afterEachArray = [NSMutableArray array];
+ self.sharedExamples = [NSMutableDictionary dictionary];
self.exampleCount = 0;
self.ranExampleCount = 0;
}
View
@@ -2,6 +2,7 @@
#import "SPTSpec.h"
#import "SPTExample.h"
#import "SPTSenTestInvocation.h"
+#import "SPTSharedExampleGroups.h"
#import <objc/runtime.h>
@interface NSObject (SPTSenTestCase)
@@ -24,6 +25,7 @@ - (void)dealloc {
}
+ (void)initialize {
+ [SPTSharedExampleGroups initialize];
SPTSpec *spec = [[SPTSpec alloc] init];
SPTSenTestCase *testCase = [[[self class] alloc] init];
objc_setAssociatedObject(self, "SPT_spec", spec, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@@ -0,0 +1,15 @@
+#import <Foundation/Foundation.h>
+#import "SpectaTypes.h"
+
+@class
+ SPTExampleGroup
+;
+
+@interface SPTSharedExampleGroups : NSObject
+
++ (void)addSharedExampleGroupWithName:(NSString *)name block:(SPTDictionaryBlock)block exampleGroup:(SPTExampleGroup *)exampleGroup;
++ (SPTDictionaryBlock)sharedExampleGroupWithName:(NSString *)name exampleGroup:(SPTExampleGroup *)exampleGroup;
++ (void)defineSharedExampleGroups;
+
+@end
+
@@ -0,0 +1,58 @@
+#import "SPTSharedExampleGroups.h"
+#import "SPTExampleGroup.h"
+#import <objc/runtime.h>
+
+NSMutableDictionary *globalSharedExampleGroups = nil;
+BOOL initialized = NO;
+
+@implementation SPTSharedExampleGroups
+
++ (void)initialize {
+ @synchronized(self) {
+ Class SPTSharedExampleGroupsClass = [SPTSharedExampleGroups class];
+ if([self class] == SPTSharedExampleGroupsClass) {
+ if(!initialized) {
+ initialized = YES;
+ globalSharedExampleGroups = [[NSMutableDictionary alloc] init];
+
+ Class *classes = NULL;
+ int numClasses = objc_getClassList(NULL, 0);
+
+ if(numClasses > 0) {
+ classes = malloc(sizeof(Class) * numClasses);
+ numClasses = objc_getClassList(classes, numClasses);
+
+ Class klass, superClass;
+ for(uint i = 0; i < numClasses; i++) {
+ klass = classes[i];
+ superClass = class_getSuperclass(klass);
+ if(superClass == SPTSharedExampleGroupsClass) {
+ [klass defineSharedExampleGroups];
+ }
+ }
+
+ free(classes);
+ }
+ }
+ }
+ }
+}
+
++ (void)addSharedExampleGroupWithName:(NSString *)name block:(SPTDictionaryBlock)block exampleGroup:(SPTExampleGroup *)exampleGroup {
+ [(exampleGroup == nil ? globalSharedExampleGroups : exampleGroup.sharedExamples) setObject:[[block copy] autorelease] forKey:name];
+}
+
++ (SPTDictionaryBlock)sharedExampleGroupWithName:(NSString *)name exampleGroup:(SPTExampleGroup *)exampleGroup {
+ SPTDictionaryBlock sharedExampleGroup = nil;
+ while(exampleGroup != nil) {
+ if((sharedExampleGroup = [exampleGroup.sharedExamples objectForKey:name])) {
+ return sharedExampleGroup;
+ }
+ exampleGroup = exampleGroup.parent;
+ }
+ return [globalSharedExampleGroups objectForKey:name];
+}
+
++ (void)defineSharedExampleGroups {}
+
+@end
View
@@ -3,16 +3,24 @@
#import "SPTSenTestCase.h"
#import "SPTSpec.h"
#import "SPTExampleGroup.h"
+#import "SPTSharedExampleGroups.h"
@interface Specta : NSObject
@end
#define SpecBegin(name) _SPT_SpecBegin(name, __FILE__, __LINE__)
#define SpecEnd _SPT_SpecEnd
+#define SharedExamplesBegin(name) _SPT_SharedExampleGroupsBegin(name)
+#define SharedExamplesEnd _SPT_SharedExampleGroupsEnd
+#define SharedExampleGroupsBegin(name) _SPT_SharedExampleGroupsBegin(name)
+#define SharedExampleGroupsEnd _SPT_SharedExampleGroupsEnd
+
#ifdef SPT_CEDAR_SYNTAX
# define SPEC_BEGIN(name) SpecBegin(name)
# define SPEC_END SpecEnd
+# define SHARED_EXAMPLE_GROUPS_BEGIN(name) SharedExamplesBegin(name)
+# define SHARED_EXAMPLE_GROUPS_END SharedExamplesEnd
#endif
void describe(NSString *name, void (^block)());
@@ -36,3 +44,9 @@ void beforeEach(void (^block)());
void afterEach(void (^block)());
void before(void (^block)());
void after(void (^block)());
+
+void sharedExamplesFor(NSString *name, void (^block)(NSDictionary *data));
+void sharedExamples(NSString *name, void (^block)(NSDictionary *data));
+
+void itShouldBehaveLike(NSString *name, NSDictionary *data);
+void itBehavesLike(NSString *name, NSDictionary *data);
View
@@ -1,4 +1,5 @@
#import "Specta.h"
+#import "SpectaTypes.h"
@implementation Specta
@end
@@ -60,3 +61,22 @@ void before(void (^block)()) {
void after(void (^block)()) {
afterEach(block);
}
+
+void sharedExamplesFor(NSString *name, void (^block)(NSDictionary *data)) {
+ [SPTSharedExampleGroups addSharedExampleGroupWithName:name block:block exampleGroup:SPT_currentGroup];
+}
+
+void sharedExamples(NSString *name, void (^block)(NSDictionary *data)) {
+ sharedExamplesFor(name, block);
+}
+
+void itShouldBehaveLike(NSString *name, NSDictionary *data) {
+ SPTDictionaryBlock block = [SPTSharedExampleGroups sharedExampleGroupWithName:name exampleGroup:SPT_currentGroup];
+ if(block) {
+ block(data);
+ }
+}
+
+void itBehavesLike(NSString *name, NSDictionary *data) {
+ itShouldBehaveLike(name, data);
+}
View
@@ -9,3 +9,13 @@
[self SPT_unsetCurrentSpec]; \
} \
@end
+
+#define _SPT_SharedExampleGroupsBegin(name) \
+@interface name##SharedExampleGroups : SPTSharedExampleGroups \
+@end \
+@implementation name##SharedExampleGroups \
++ (void)defineSharedExampleGroups {
+
+#define _SPT_SharedExampleGroupsEnd \
+} \
+@end
View
@@ -1 +1,2 @@
typedef void (^SPTVoidBlock)();
+typedef void (^SPTDictionaryBlock)();
Oops, something went wrong.

0 comments on commit 2aa3cd9

Please sign in to comment.