diff --git a/Classes/Core/Examples/KWSharedExample.h b/Classes/Core/Examples/KWSharedExample.h new file mode 100644 index 00000000..0de1d926 --- /dev/null +++ b/Classes/Core/Examples/KWSharedExample.h @@ -0,0 +1,23 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import + +typedef void (^KWSharedExampleBlock)(Class describedClass); + +@interface KWSharedExample : NSObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) KWSharedExampleBlock block; + +- (id)initWithName:(NSString *)name block:(KWSharedExampleBlock)block; + +@end + +#pragma mark - Building Shared Example Groups + +void sharedExamplesFor(NSString *name, KWSharedExampleBlock block); +void itBehavesLike(NSString *name, Class describedClass); diff --git a/Classes/Core/Examples/KWSharedExample.m b/Classes/Core/Examples/KWSharedExample.m new file mode 100644 index 00000000..ac94e398 --- /dev/null +++ b/Classes/Core/Examples/KWSharedExample.m @@ -0,0 +1,40 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import "KWSharedExample.h" +#import "KWSharedExampleRegistry.h" +#import "KWExample.h" + +@implementation KWSharedExample + +#pragma mark - Initializing + +- (id)initWithName:(NSString *)name block:(KWSharedExampleBlock)block { + NSParameterAssert(name); + NSParameterAssert(block); + + self = [super init]; + if (self) { + _name = name; + _block = block; + } + return self; +} + +@end + +#pragma mark - Building Example Groups + +void sharedExamplesFor(NSString *name, KWSharedExampleBlock block) { + KWSharedExample *sharedExample = [[KWSharedExample alloc] initWithName:name block:block]; + [[KWSharedExampleRegistry sharedRegistry] registerSharedExample:sharedExample]; +} + +void itBehavesLike(NSString *name, Class describedClass) { + KWSharedExample *sharedExample = [[KWSharedExampleRegistry sharedRegistry] sharedExampleForName:name]; + NSString *description = [NSString stringWithFormat:@"behaves like %@", sharedExample.name]; + context(description, ^{ sharedExample.block(describedClass); }); +} diff --git a/Classes/Core/Examples/KWSharedExampleRegistry.h b/Classes/Core/Examples/KWSharedExampleRegistry.h new file mode 100644 index 00000000..51c15633 --- /dev/null +++ b/Classes/Core/Examples/KWSharedExampleRegistry.h @@ -0,0 +1,17 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import + +@class KWSharedExample; + +@interface KWSharedExampleRegistry : NSObject + ++ (instancetype)sharedRegistry; +- (KWSharedExample *)sharedExampleForName:(NSString *)name; +- (void)registerSharedExample:(KWSharedExample *)sharedExample; + +@end diff --git a/Classes/Core/Examples/KWSharedExampleRegistry.m b/Classes/Core/Examples/KWSharedExampleRegistry.m new file mode 100644 index 00000000..69197b65 --- /dev/null +++ b/Classes/Core/Examples/KWSharedExampleRegistry.m @@ -0,0 +1,66 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import "KWSharedExampleRegistry.h" +#import "KWSharedExample.h" + +@interface KWSharedExampleRegistry () +@property (nonatomic, strong) NSMutableDictionary *sharedExamples; +@end + +@implementation KWSharedExampleRegistry + +#pragma mark - Initializing + ++ (instancetype)sharedRegistry { + static KWSharedExampleRegistry *sharedRegistry = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedRegistry = [self new]; + + }); + return sharedRegistry; +} + +- (id)init { + self = [super init]; + if (self) { + _sharedExamples = [NSMutableDictionary dictionary]; + } + return self; +} + +#pragma mark - Public Interface + +- (KWSharedExample *)sharedExampleForName:(NSString *)name { + [self raiseIfSharedExampleNotRegistered:name]; + return [_sharedExamples objectForKey:name]; +} + +- (void)registerSharedExample:(KWSharedExample *)sharedExample { + [self raiseIfSharedExampleAlreadyRegistered:sharedExample]; + [_sharedExamples setObject:sharedExample forKey:sharedExample.name]; +} + +#pragma mark - Internal Methods + +- (void)raiseIfSharedExampleNotRegistered:(NSString *)name { + if (![_sharedExamples objectForKey:name]) { + [NSException raise:NSInternalInconsistencyException + format:@"Kiwi shared example error: No shared example registered for '%@'", + name]; + } +} + +- (void)raiseIfSharedExampleAlreadyRegistered:(KWSharedExample *)sharedExample { + if ([_sharedExamples objectForKey:sharedExample.name]) { + [NSException raise:NSInternalInconsistencyException + format:@"Kiwi shared example error: Shared example already registered for '%@'", + sharedExample.name]; + } +} + +@end diff --git a/Classes/Core/KWFormatter.m b/Classes/Core/KWFormatter.m index f12917e2..31a4152d 100644 --- a/Classes/Core/KWFormatter.m +++ b/Classes/Core/KWFormatter.m @@ -34,7 +34,7 @@ + (NSString *)formatObjectIncludingClass:(id)anObject { } -#pragma mark - Private +#pragma mark - Internal Methods + (NSString *)formattedCollection:(id)collection { diff --git a/Classes/Core/KWMatcherFactory.m b/Classes/Core/KWMatcherFactory.m index db07795d..38591e93 100644 --- a/Classes/Core/KWMatcherFactory.m +++ b/Classes/Core/KWMatcherFactory.m @@ -117,7 +117,7 @@ - (KWMatcher *)matcherFromInvocation:(NSInvocation *)anInvocation subject:(id)su return [[matcherClass alloc] initWithSubject:subject]; } -#pragma mark - Private methods +#pragma mark - Internal Methods - (Class)matcherClassForSelector:(SEL)aSelector subject:(id)anObject { NSArray *matcherClassChain = self.matcherClassChains[NSStringFromSelector(aSelector)]; diff --git a/Classes/Core/KWStringUtilities.h b/Classes/Core/KWStringUtilities.h index 90264d94..055a1715 100644 --- a/Classes/Core/KWStringUtilities.h +++ b/Classes/Core/KWStringUtilities.h @@ -15,5 +15,4 @@ BOOL KWStringHasWord(NSString *string, NSString *word); #pragma mark - Getting Type Encodings NSString *KWEncodingWithObjCTypes(const char *firstType, ...) NS_REQUIRES_NIL_TERMINATION; -NSString *KWEncodingForVoidMethod(void); NSString *KWEncodingForDefaultMethod(void); diff --git a/Classes/Core/KWStringUtilities.m b/Classes/Core/KWStringUtilities.m index 4e17197e..38ba0246 100644 --- a/Classes/Core/KWStringUtilities.m +++ b/Classes/Core/KWStringUtilities.m @@ -83,10 +83,6 @@ BOOL KWStringHasWord(NSString *string, NSString *word) { return encoding; } -NSString *KWEncodingForVoidMethod(void) { - return KWEncodingWithObjCTypes(@encode(void), @encode(id), @encode(SEL), nil); -} - NSString *KWEncodingForDefaultMethod(void) { return KWEncodingWithObjCTypes(@encode(id), @encode(id), @encode(SEL), nil); } diff --git a/Classes/Core/Kiwi.h b/Classes/Core/Kiwi.h index 9f27af96..5e007906 100644 --- a/Classes/Core/Kiwi.h +++ b/Classes/Core/Kiwi.h @@ -43,6 +43,7 @@ extern "C" { #import "KWExampleSuiteBuilder.h" #import "KWExampleNode.h" #import "KWExampleNodeVisitor.h" +#import "KWSharedExample.h" #import "KWExistVerifier.h" #import "KWExpectationType.h" #import "KWFailure.h" diff --git a/Classes/Core/KiwiMacros.h b/Classes/Core/KiwiMacros.h index d754a094..af932ed1 100644 --- a/Classes/Core/KiwiMacros.h +++ b/Classes/Core/KiwiMacros.h @@ -29,9 +29,9 @@ #pragma mark - Support Macros #define KW_THIS_CALLSITE [KWCallSite callSiteWithFilename:@__FILE__ lineNumber:__LINE__] -#define KW_ADD_EXIST_VERIFIER(expectationType) [self addExistVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE] -#define KW_ADD_MATCH_VERIFIER(expectationType) [self addMatchVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE] -#define KW_ADD_ASYNC_VERIFIER(expectationType, timeOut, wait) [self addAsyncVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE timeout:timeOut shouldWait:wait] +#define KW_ADD_EXIST_VERIFIER(expectationType) [KWSpec addExistVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE] +#define KW_ADD_MATCH_VERIFIER(expectationType) [KWSpec addMatchVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE] +#define KW_ADD_ASYNC_VERIFIER(expectationType, timeOut, wait) [KWSpec addAsyncVerifierWithExpectationType:expectationType callSite:KW_THIS_CALLSITE timeout:timeOut shouldWait:wait] #pragma mark - Keywords @@ -109,3 +109,21 @@ } \ \ @end + +// Used to ensure that shared examples are registered before any +// examples are evaluated. The name parameter is not used except +// to define a category. Therefore, it must be unique. +#define SHARED_EXAMPLES_BEGIN(name) \ + \ + @interface KWSharedExample (name) \ + \ + @end \ + \ + @implementation KWSharedExample (name) \ + \ + + (void)load { \ + +#define SHARED_EXAMPLES_END \ + } \ + \ + @end \ diff --git a/Kiwi.xcodeproj/project.pbxproj b/Kiwi.xcodeproj/project.pbxproj index 71b289d6..d1182cda 100755 --- a/Kiwi.xcodeproj/project.pbxproj +++ b/Kiwi.xcodeproj/project.pbxproj @@ -785,11 +785,18 @@ DA084E6C17E3838100592D5A /* KWRegularExpressionPatternMatcher.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4E3C5DB01716C34900835B62 /* KWRegularExpressionPatternMatcher.h */; }; DA084E6D17E3838100592D5A /* KWSymbolicator.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C533F7D117462CAA000CAB02 /* KWSymbolicator.h */; }; DA084E6E17E3838100592D5A /* NSProxy+KiwiVerifierAdditions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9F820DB616BB6748003A1BA5 /* NSProxy+KiwiVerifierAdditions.h */; }; + DA3EAD0818A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3EAD0718A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m */; }; DA3EAD0A18A86E5600EBBF57 /* KWUserDefinedMatcherFunctionalTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3EAD0918A86E5600EBBF57 /* KWUserDefinedMatcherFunctionalTest.m */; }; DA92B2A617E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA92B2A417E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.h */; }; DA92B2A717E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92B2A517E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.m */; }; DAA35A2317E3CF6600C41AE2 /* libKiwi-XCTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA084E7317E3838100592D5A /* libKiwi-XCTest.a */; }; DAAC61CB17E75B50000165F6 /* KWObjCUtilitiesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAC61CA17E75B50000165F6 /* KWObjCUtilitiesTest.m */; }; + DAB1AF9418A53E2400CACD90 /* KWSharedExample.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB1AF9018A53E2400CACD90 /* KWSharedExample.h */; }; + DAB1AF9518A53E2400CACD90 /* KWSharedExample.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB1AF9118A53E2400CACD90 /* KWSharedExample.m */; }; + DAB1AF9618A53E2400CACD90 /* KWSharedExampleRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB1AF9218A53E2400CACD90 /* KWSharedExampleRegistry.h */; }; + DAB1AF9718A53E2400CACD90 /* KWSharedExampleRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB1AF9318A53E2400CACD90 /* KWSharedExampleRegistry.m */; }; + DAB1AF9B18A53E9900CACD90 /* KWSharedExampleRegistryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB1AF9918A53E9900CACD90 /* KWSharedExampleRegistryTest.m */; }; + DAB1AF9C18A53E9900CACD90 /* KWSharedExampleTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB1AF9A18A53E9900CACD90 /* KWSharedExampleTest.m */; }; DABFFFEC17E3CC3800E79FB4 /* Kiwi-XCTest-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = DABFFFEB17E3CC2B00E79FB4 /* Kiwi-XCTest-Prefix.pch */; }; F5015CBD1158404E002E9A98 /* libKiwi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F5015B9F11583A77002E9A98 /* libKiwi.a */; }; F53B5E43115B33FC0022BC0B /* KWContainMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F53B5E42115B33FC0022BC0B /* KWContainMatcherTest.m */; }; @@ -1286,10 +1293,17 @@ DA084D5317E381C700592D5A /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; DA084D5A17E3831E00592D5A /* KWXCFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWXCFunctionalTest.m; sourceTree = ""; }; DA084E7317E3838100592D5A /* libKiwi-XCTest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libKiwi-XCTest.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DA3EAD0718A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleFunctionalTest.m; sourceTree = ""; }; DA3EAD0918A86E5600EBBF57 /* KWUserDefinedMatcherFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWUserDefinedMatcherFunctionalTest.m; sourceTree = ""; }; DA92B2A417E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SenTestSuite+KiwiAdditions.h"; sourceTree = ""; }; DA92B2A517E6A3EF0062F84D /* SenTestSuite+KiwiAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SenTestSuite+KiwiAdditions.m"; sourceTree = ""; }; DAAC61CA17E75B50000165F6 /* KWObjCUtilitiesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWObjCUtilitiesTest.m; sourceTree = ""; }; + DAB1AF9018A53E2400CACD90 /* KWSharedExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWSharedExample.h; sourceTree = ""; }; + DAB1AF9118A53E2400CACD90 /* KWSharedExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExample.m; sourceTree = ""; }; + DAB1AF9218A53E2400CACD90 /* KWSharedExampleRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWSharedExampleRegistry.h; sourceTree = ""; }; + DAB1AF9318A53E2400CACD90 /* KWSharedExampleRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleRegistry.m; sourceTree = ""; }; + DAB1AF9918A53E9900CACD90 /* KWSharedExampleRegistryTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleRegistryTest.m; sourceTree = ""; }; + DAB1AF9A18A53E9900CACD90 /* KWSharedExampleTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleTest.m; sourceTree = ""; }; DABFFFEB17E3CC2B00E79FB4 /* Kiwi-XCTest-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Kiwi-XCTest-Prefix.pch"; sourceTree = ""; }; F5015B9F11583A77002E9A98 /* libKiwi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKiwi.a; sourceTree = BUILT_PRODUCTS_DIR; }; F5015C9E11584017002E9A98 /* KiwiTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KiwiTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1458,6 +1472,7 @@ 37934CE3177F661400D07AE8 /* Core */ = { isa = PBXGroup; children = ( + DAB1AF8F18A53E2400CACD90 /* Examples */, C533F7D117462CAA000CAB02 /* KWSymbolicator.h */, C533F7D217462CAA000CAB02 /* KWSymbolicator.m */, 9F982C3A16A802920030A0B1 /* Kiwi.h */, @@ -1737,6 +1752,27 @@ path = SenTestingKit; sourceTree = ""; }; + DAB1AF8F18A53E2400CACD90 /* Examples */ = { + isa = PBXGroup; + children = ( + DAB1AF9018A53E2400CACD90 /* KWSharedExample.h */, + DAB1AF9118A53E2400CACD90 /* KWSharedExample.m */, + DAB1AF9218A53E2400CACD90 /* KWSharedExampleRegistry.h */, + DAB1AF9318A53E2400CACD90 /* KWSharedExampleRegistry.m */, + ); + path = Examples; + sourceTree = ""; + }; + DAB1AF9818A53E9900CACD90 /* Shared Examples */ = { + isa = PBXGroup; + children = ( + DAB1AF9918A53E9900CACD90 /* KWSharedExampleRegistryTest.m */, + DAB1AF9A18A53E9900CACD90 /* KWSharedExampleTest.m */, + DA3EAD0718A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m */, + ); + path = "Shared Examples"; + sourceTree = ""; + }; F5015B4D1158396B002E9A98 /* Classes */ = { isa = PBXGroup; children = ( @@ -1753,6 +1789,7 @@ F5015BE211583C27002E9A98 /* Tests */ = { isa = PBXGroup; children = ( + DAB1AF9818A53E9900CACD90 /* Shared Examples */, 89F9CB7816B1BE0E00E87D34 /* Functional */, 080E96DDFE201D6D7F000001 /* Test Classes */, F5A1E60711743223002223E1 /* Specs */, @@ -2059,6 +2096,7 @@ files = ( 9F982CE016A802920030A0B1 /* Kiwi.h in Headers */, 88E0EC571852D281008E998A /* KWLet.h in Headers */, + DAB1AF9618A53E2400CACD90 /* KWSharedExampleRegistry.h in Headers */, 9F982CE216A802920030A0B1 /* KiwiBlockMacros.h in Headers */, 9F982CE416A802920030A0B1 /* KiwiConfiguration.h in Headers */, 9F982CE616A802920030A0B1 /* KiwiMacros.h in Headers */, @@ -2156,6 +2194,7 @@ 4A6A09EF185F93D70053DAE2 /* TestSuiteConfigurationAdditions.h in Headers */, C533F7D317462CAA000CAB02 /* KWSymbolicator.h in Headers */, 37828763177F860B00BCD40F /* Kiwi-Prefix.pch in Headers */, + DAB1AF9418A53E2400CACD90 /* KWSharedExample.h in Headers */, 4A71048017CC016600A7B718 /* KWLetNode.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2604,6 +2643,7 @@ 9F982D7E16A802920030A0B1 /* KWGenericMatcher.m in Sources */, 9F982D8216A802920030A0B1 /* KWGenericMatchingAdditions.m in Sources */, 9F982D8616A802920030A0B1 /* KWHaveMatcher.m in Sources */, + DAB1AF9518A53E2400CACD90 /* KWSharedExample.m in Sources */, 9F982D8A16A802920030A0B1 /* KWHaveValueMatcher.m in Sources */, 9F982D9016A802920030A0B1 /* KWInequalityMatcher.m in Sources */, 9F982D9416A802920030A0B1 /* KWIntercept.m in Sources */, @@ -2649,6 +2689,7 @@ 4E3C5DB41716C34900835B62 /* KWRegularExpressionPatternMatcher.m in Sources */, 4E7659AB172DAC6500105B93 /* KWContainStringMatcher.m in Sources */, C533F7D517462CAA000CAB02 /* KWSymbolicator.m in Sources */, + DAB1AF9718A53E2400CACD90 /* KWSharedExampleRegistry.m in Sources */, 4A8699B917E9B3CE007F250E /* KWLetNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2665,6 +2706,7 @@ F5C36E93115C9F0700425FDA /* KWReceiveMatcherTest.m in Sources */, F5D7C8D411643C2900758FEA /* KWDeviceInfoTest.m in Sources */, F54A4B1E11733D98002442C5 /* KWBeKindOfClassMatcherTest.m in Sources */, + DAB1AF9B18A53E9900CACD90 /* KWSharedExampleRegistryTest.m in Sources */, F54A4BD511734750002442C5 /* KWBeMemberOfClassMatcherTest.m in Sources */, F54A4C0111734975002442C5 /* KWConformToProtocolMatcherTest.m in Sources */, F5A1E67911743B92002223E1 /* KWBeWithinMatcherTest.m in Sources */, @@ -2697,6 +2739,7 @@ 9F982A3B16A801800030A0B1 /* Fighter.m in Sources */, 9F982A3C16A801800030A0B1 /* Galaxy.m in Sources */, 9F982A3D16A801800030A0B1 /* KiwiAppDelegate.m in Sources */, + DAB1AF9C18A53E9900CACD90 /* KWSharedExampleTest.m in Sources */, 9F982A3E16A801800030A0B1 /* KiwiViewController.m in Sources */, 9F982A3F16A801800030A0B1 /* Robot.m in Sources */, 9F982A4016A801800030A0B1 /* SpaceShip.m in Sources */, @@ -2707,6 +2750,7 @@ 9F820DBC16BB6808003A1BA5 /* KWChangeMatcherTest.m in Sources */, 492F3A7A16D5F7DC008E3C49 /* KWFailureTest.m in Sources */, 89861D9416FE0EE5008CE99D /* KWFormatterTest.m in Sources */, + DA3EAD0818A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m in Sources */, C10F0370170C7C2D0031FE64 /* KWBeSubclassOfClassMatcherTest.m in Sources */, 4E3C5DB81716C68000835B62 /* KWRegularExpressionPatternMatcherTest.m in Sources */, 4E7659B0172DAE4D00105B93 /* KWContainStringMatcherTest.m in Sources */, diff --git a/Tests/Shared Examples/KWSharedExampleFunctionalTest.m b/Tests/Shared Examples/KWSharedExampleFunctionalTest.m new file mode 100644 index 00000000..7710ecf4 --- /dev/null +++ b/Tests/Shared Examples/KWSharedExampleFunctionalTest.m @@ -0,0 +1,36 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import "Kiwi.h" +#import "Cruiser.h" +#import "Carrier.h" + +SPEC_BEGIN(KWSharedExampleFunctionalTest) + +describe(@"Cruiser", ^{ + itBehavesLike(@"a cruiser", [Cruiser class]); +}); + +describe(@"Carrier", ^{ + itBehavesLike(@"a cruiser", [Carrier class]); +}); + +SPEC_END + +SHARED_EXAMPLES_BEGIN(TestClasses) + +sharedExamplesFor(@"a cruiser", ^(Class describedClass) { + __block Cruiser *cruiser = nil; + beforeEach(^{ + cruiser = [[describedClass alloc] initWithCallsign:@"Planet Express"]; + }); + + it(@"has a callsign", ^{ + [[cruiser.callsign should] equal:@"Planet Express"]; + }); +}); + +SHARED_EXAMPLES_END diff --git a/Tests/Shared Examples/KWSharedExampleRegistryTest.m b/Tests/Shared Examples/KWSharedExampleRegistryTest.m new file mode 100644 index 00000000..b6c068a7 --- /dev/null +++ b/Tests/Shared Examples/KWSharedExampleRegistryTest.m @@ -0,0 +1,49 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import +#import "KWSharedExampleRegistry.h" +#import "KWSharedExample.h" + +@interface KWSharedExampleRegistryTest : SenTestCase + +@end + +@implementation KWSharedExampleRegistryTest + +- (void)testRegisterSharedExample { + KWSharedExample *sharedExample = [[KWSharedExample alloc] initWithName:@"LGTM" + block:^(Class describedClass) {}]; + [[KWSharedExampleRegistry sharedRegistry] registerSharedExample:sharedExample]; + + STAssertEqualObjects([[KWSharedExampleRegistry sharedRegistry] sharedExampleForName:@"LGTM"], + sharedExample, + @"Shared example was not registered."); +} + +- (void)testRegisterSharedExampleWithSameNameRaises { + KWSharedExample *firstSharedExample = + [[KWSharedExample alloc] initWithName:@"ASAP" + block:^(Class describedClass) { + NSLog(@"This example will be registered."); + }]; + KWSharedExample *secondSharedExample = + [[KWSharedExample alloc] initWithName:@"ASAP" + block:^(Class describedClass) { + NSLog(@"This example will throw."); + }]; + + [[KWSharedExampleRegistry sharedRegistry] registerSharedExample:firstSharedExample]; + STAssertThrows([[KWSharedExampleRegistry sharedRegistry] registerSharedExample:secondSharedExample], + @"Registering shared example with identical name did not raise."); +} + +- (void)testSharedExampleLookupRaisesIfNonexistent { + STAssertThrows([[KWSharedExampleRegistry sharedRegistry] sharedExampleForName:@"XHTML"], + @"Lookup for unregistered shared example did not raise."); +} + +@end diff --git a/Tests/Shared Examples/KWSharedExampleTest.m b/Tests/Shared Examples/KWSharedExampleTest.m new file mode 100644 index 00000000..39dcd4be --- /dev/null +++ b/Tests/Shared Examples/KWSharedExampleTest.m @@ -0,0 +1,51 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2014 Allen Ding. All rights reserved. +// + +#import +#import "KWSharedExample.h" +#import "KWSharedExampleRegistry.h" +#import "KWExample.h" + +@interface KWSharedExampleTest : SenTestCase + +@end + +@implementation KWSharedExampleTest + +- (void)testSharedExampleMustHaveNameParameter { + STAssertThrows([[KWSharedExample alloc] initWithName:nil block:nil], + @"Unnamed shared example was created"); +} + +- (void)testSharedExampleMustHaveBlockParameter { + STAssertThrows([[KWSharedExample alloc] initWithName:@"FTW" + block:nil], + @"Shared example was created without a corresponding context block"); +} + +- (void)testSharedExamplesForRegistersTheSharedExample { + sharedExamplesFor(@"FTTP", ^(Class sharedExample) {}); + STAssertEqualObjects([[KWSharedExampleRegistry sharedRegistry] sharedExampleForName:@"FTTP"].name, + @"FTTP", + @"Shared example was not registered."); +} + +- (void)testItBehavesLikeExecutesTheBlock { + __block NSNumber *blockWasCalled = @NO; + sharedExamplesFor(@"ESP", ^(Class describedClass) { + beforeAll(^{ + blockWasCalled = @YES; + }); + context(@"with LSD", ^{ + blockWasCalled = @YES; + }); + }); + + STAssertFalse([blockWasCalled boolValue], + @"Blocks in shared example were executed prematurely."); +} + +@end