Permalink
Browse files

Inital

  • Loading branch information...
0 parents commit e5ad3e0e20b11bba0bb3b630d82ec5c19d2c43ec @joecannatti committed Dec 23, 2010
Showing with 9,897 additions and 0 deletions.
  1. +39 −0 .gitignore
  2. +108 −0 AboutValueAssertions.m
  3. +21 −0 Classes/ObjectiveCKoansAppDelegate.h
  4. +35 −0 Classes/ObjectiveCKoansAppDelegate.m
  5. +22 −0 Kiwi/KWAfterAllNode.h
  6. +30 −0 Kiwi/KWAfterAllNode.m
  7. +22 −0 Kiwi/KWAfterEachNode.h
  8. +30 −0 Kiwi/KWAfterEachNode.m
  9. +23 −0 Kiwi/KWBeBetweenMatcher.h
  10. +79 −0 Kiwi/KWBeBetweenMatcher.m
  11. +20 −0 Kiwi/KWBeEmptyMatcher.h
  12. +74 −0 Kiwi/KWBeEmptyMatcher.m
  13. +20 −0 Kiwi/KWBeIdenticalToMatcher.h
  14. +72 −0 Kiwi/KWBeIdenticalToMatcher.m
  15. +20 −0 Kiwi/KWBeKindOfClassMatcher.h
  16. +55 −0 Kiwi/KWBeKindOfClassMatcher.m
  17. +20 −0 Kiwi/KWBeMemberOfClassMatcher.h
  18. +55 −0 Kiwi/KWBeMemberOfClassMatcher.m
  19. +23 −0 Kiwi/KWBeTrueMatcher.h
  20. +69 −0 Kiwi/KWBeTrueMatcher.m
  21. +22 −0 Kiwi/KWBeWithinMatcher.h
  22. +109 −0 Kiwi/KWBeWithinMatcher.m
  23. +17 −0 Kiwi/KWBeZeroMatcher.h
  24. +48 −0 Kiwi/KWBeZeroMatcher.m
  25. +22 −0 Kiwi/KWBeforeAllNode.h
  26. +30 −0 Kiwi/KWBeforeAllNode.m
  27. +22 −0 Kiwi/KWBeforeEachNode.h
  28. +30 −0 Kiwi/KWBeforeEachNode.m
  29. +37 −0 Kiwi/KWBlock.h
  30. +67 −0 Kiwi/KWBlock.m
  31. +43 −0 Kiwi/KWBlockNode.h
  32. +55 −0 Kiwi/KWBlockNode.m
  33. +28 −0 Kiwi/KWBlockRaiseMatcher.h
  34. +125 −0 Kiwi/KWBlockRaiseMatcher.m
  35. +33 −0 Kiwi/KWCallSite.h
  36. +56 −0 Kiwi/KWCallSite.m
  37. +20 −0 Kiwi/KWConformToProtocolMatcher.h
  38. +55 −0 Kiwi/KWConformToProtocolMatcher.m
  39. +31 −0 Kiwi/KWContainMatcher.h
  40. +104 −0 Kiwi/KWContainMatcher.m
  41. +71 −0 Kiwi/KWContextNode.h
  42. +105 −0 Kiwi/KWContextNode.m
  43. +15 −0 Kiwi/KWCountType.h
  44. +17 −0 Kiwi/KWDeviceInfo.h
  45. +33 −0 Kiwi/KWDeviceInfo.m
  46. +20 −0 Kiwi/KWEqualMatcher.h
  47. +69 −0 Kiwi/KWEqualMatcher.m
  48. +37 −0 Kiwi/KWExampleGroup.h
  49. +89 −0 Kiwi/KWExampleGroup.m
  50. +44 −0 Kiwi/KWExampleGroupBuilder.h
  51. +187 −0 Kiwi/KWExampleGroupBuilder.m
  52. +22 −0 Kiwi/KWExampleNode.h
  53. +36 −0 Kiwi/KWExampleNodeVisitor.h
  54. +35 −0 Kiwi/KWExistVerifier.h
  55. +70 −0 Kiwi/KWExistVerifier.m
  56. +14 −0 Kiwi/KWExpectationType.h
  57. +37 −0 Kiwi/KWFailure.h
  58. +65 −0 Kiwi/KWFailure.m
  59. +16 −0 Kiwi/KWFormatter.h
  60. +38 −0 Kiwi/KWFormatter.m
  61. +54 −0 Kiwi/KWHaveMatcher.h
  62. +254 −0 Kiwi/KWHaveMatcher.m
  63. +33 −0 Kiwi/KWInequalityMatcher.h
  64. +117 −0 Kiwi/KWInequalityMatcher.m
  65. +47 −0 Kiwi/KWIntercept.h
  66. +278 −0 Kiwi/KWIntercept.m
  67. +42 −0 Kiwi/KWInvocationCapturer.h
  68. +97 −0 Kiwi/KWInvocationCapturer.m
  69. +24 −0 Kiwi/KWItNode.h
  70. +30 −0 Kiwi/KWItNode.m
  71. +45 −0 Kiwi/KWMatchVerifier.h
  72. +164 −0 Kiwi/KWMatchVerifier.m
  73. +48 −0 Kiwi/KWMatcher.h
  74. +82 −0 Kiwi/KWMatcher.m
  75. +42 −0 Kiwi/KWMatcherFactory.h
  76. +122 −0 Kiwi/KWMatcherFactory.m
  77. +43 −0 Kiwi/KWMatching.h
  78. +49 −0 Kiwi/KWMessagePattern.h
  79. +223 −0 Kiwi/KWMessagePattern.m
  80. +16 −0 Kiwi/KWMessageSpying.h
  81. +53 −0 Kiwi/KWMessageTracker.h
  82. +151 −0 Kiwi/KWMessageTracker.m
  83. +88 −0 Kiwi/KWMock.h
  84. +556 −0 Kiwi/KWMock.m
  85. +19 −0 Kiwi/KWNull.h
  86. +47 −0 Kiwi/KWNull.m
  87. +31 −0 Kiwi/KWObjCUtilities.h
  88. +97 −0 Kiwi/KWObjCUtilities.m
  89. +39 −0 Kiwi/KWPendingNode.h
  90. +55 −0 Kiwi/KWPendingNode.m
  91. +25 −0 Kiwi/KWRaiseMatcher.h
  92. +121 −0 Kiwi/KWRaiseMatcher.m
  93. +61 −0 Kiwi/KWReceiveMatcher.h
  94. +308 −0 Kiwi/KWReceiveMatcher.m
  95. +39 −0 Kiwi/KWRegisterMatchersNode.h
  96. +55 −0 Kiwi/KWRegisterMatchersNode.m
  97. +18 −0 Kiwi/KWReporting.h
  98. +20 −0 Kiwi/KWRespondToSelectorMatcher.h
  99. +55 −0 Kiwi/KWRespondToSelectorMatcher.m
  100. +49 −0 Kiwi/KWSpec.h
  101. +321 −0 Kiwi/KWSpec.m
  102. +20 −0 Kiwi/KWStringUtilities.h
  103. +90 −0 Kiwi/KWStringUtilities.m
  104. +37 −0 Kiwi/KWStub.h
  105. +131 −0 Kiwi/KWStub.m
  106. +44 −0 Kiwi/KWTestCase.h
  107. +185 −0 Kiwi/KWTestCase.m
  108. +96 −0 Kiwi/KWValue.h
  109. +352 −0 Kiwi/KWValue.m
  110. +21 −0 Kiwi/KWVerifying.h
  111. +18 −0 Kiwi/KWWorkarounds.h
  112. +26 −0 Kiwi/KWWorkarounds.m
  113. +73 −0 Kiwi/Kiwi.h
  114. +28 −0 Kiwi/KiwiConfiguration.h
  115. +67 −0 Kiwi/KiwiMacros.h
  116. +28 −0 Kiwi/NSInvocation+KiwiAdditions.h
  117. +93 −0 Kiwi/NSInvocation+KiwiAdditions.m
  118. +17 −0 Kiwi/NSMethodSignature+KiwiAdditions.h
  119. +22 −0 Kiwi/NSMethodSignature+KiwiAdditions.m
  120. +31 −0 Kiwi/NSNumber+KiwiAdditions.h
  121. +111 −0 Kiwi/NSNumber+KiwiAdditions.m
  122. +20 −0 Kiwi/NSObject+KiwiMockAdditions.h
  123. +31 −0 Kiwi/NSObject+KiwiMockAdditions.m
  124. +36 −0 Kiwi/NSObject+KiwiStubAdditions.h
  125. +108 −0 Kiwi/NSObject+KiwiStubAdditions.m
  126. +19 −0 Kiwi/NSObject+KiwiVerifierAdditions.h
  127. +26 −0 Kiwi/NSObject+KiwiVerifierAdditions.m
  128. +16 −0 Kiwi/NSValue+KiwiAdditions.h
  129. +24 −0 Kiwi/NSValue+KiwiAdditions.m
  130. +10 −0 KoansIncludes.h
  131. +20 −0 KoansTests-Info.plist
  132. +424 −0 MainWindow.xib
  133. +30 −0 ObjectiveCKoans-Info.plist
  134. +783 −0 ObjectiveCKoans.xcodeproj/project.pbxproj
  135. +14 −0 ObjectiveCKoans_Prefix.pch
  136. +17 −0 main.m
39 .gitignore
@@ -0,0 +1,39 @@
+# Mac OS X Finder and whatnot
+.DS_Store
+
+
+# Sparkle distribution Private Key (Don't check me in!)
+dsa_priv.pem
+
+
+# XCode (and ancestors) per-user config (very noisy, and not relevant)
+*.mode1
+*.mode1v3
+*.mode2v3
+*.perspective
+*.perspectivev3
+*.pbxuser
+
+
+# Generated files
+VersionX-revision.h
+
+
+# build products
+build/
+*.[oa]
+
+# Other source repository archive directories (protects when importing)
+.hg
+.svn
+CVS
+
+
+# automatic backup files
+*~.nib
+*.swp
+*~
+*(Autosaved).rtfd/
+Backup[ ]of[ ]*.pages/
+Backup[ ]of[ ]*.key/
+Backup[ ]of[ ]*.numbers/
108 AboutValueAssertions.m
@@ -0,0 +1,108 @@
+//
+// AboutAssertions.m
+// ObjectiveCKoans
+//
+// Created by Joe Cannatti on 12/23/10.
+// Copyright 2010 Puppy Sound Software. All rights reserved.
+//
+
+#import "Kiwi.h"
+#import "KoansIncludes.h"
+
+SPEC_BEGIN(AboutValueAssertions)
+
+describe(@"Value Assertions", ^{
+
+ it(@"can assert truth", ^{
+ [[theValue(NO) should] beTrue];
+ });
+
+ it(@"can assert lies", ^{
+ [[theValue(YES) should] beFalse];
+ });
+
+ context(@"can assert equality", ^{
+
+ __block int expectedValue;
+ __block int actualValue;
+
+ beforeEach(^{
+ actualValue = 1 + 1;
+ });
+
+ it(@"in an ugly way", ^{
+ [[theValue(actualValue == 3) should] beTrue];
+ });
+
+ it(@"in a pretty way", ^{
+ [[theValue(actualValue) should] equal:theValue(3)];
+ });
+
+ });
+
+ it(@"sometimes will ask you to fill in a value", ^{
+ [[theValue(2) should] equal:__];
+ });
+
+ it(@"can assert that a variable contains nil", ^{
+ NSObject *object = [NSObject new];
+ [object shouldBeNil];
+ });
+
+ it(@"can assert that a variable does not contains nil", ^{
+ NSObject *object = nil;
+ [object shouldNotBeNil];
+ });
+
+ it(@"can assert that two objects are equal", ^{
+ [[@"Panda" should] equal:@"Panda1"];
+ });
+
+ it(@"can assert that two objects are not equal", ^{
+ [[@"Panda" shouldNot] equal:@"Panda"];
+ });
+
+ it(@"can assert that floating point values are equal within a delta", ^{
+ //NOTE: float vs double precsion is what makes this unequal
+ [[theValue(22.0f/7.0f) should] equal:(22.0/7.0) withDelta:0.000f];
+ });
+
+ it(@"can assert that a value is within a range", ^{
+ [[theValue(4) should] beWithin:theValue(4) of:theValue(77)];
+ });
+
+ it(@"can assert that a value is less than another value", ^{
+ [[theValue(4) should] beLessThan:theValue(4)];
+ });
+
+ it(@"can assert that a value is greater than another value", ^{
+ [[theValue(4) should] beGreaterThan:theValue(4)];
+ });
+
+ it(@"can assert that a value is less than or equal to another value", ^{
+ [[theValue(4) should] beLessThanOrEqualTo:theValue(3)];
+ });
+
+ it(@"can assert that a value is greater than or equal to another value", ^{
+ [[theValue(4) should] beGreaterThanOrEqualTo:theValue(5)];
+ });
+
+ it(@"can assert that a value is between to values", ^{
+ [[theValue(4) should] beBetween:theValue(5) and:theValue(7)];
+ });
+
+ it(@"can assert two variable contain the same pointer", ^{
+ //IdenticalTo means identical pointers
+ //but the compiler is smart about this and will use the same object if you do:
+ //NSString *panda = @"panda";
+ //NSString *samePanda = @"panda";
+ //mutableCopy is called to force a truly different instance and fail the test
+
+ NSString *panda = @"panda";
+ NSString *samePanda = [panda mutableCopy];
+ [[panda should] beIdenticalTo:samePanda];
+ });
+
+});
+
+SPEC_END
21 Classes/ObjectiveCKoansAppDelegate.h
@@ -0,0 +1,21 @@
+//
+// ObjectiveCKoansAppDelegate.h
+// ObjectiveCKoans
+//
+// Created by Joe Cannatti on 12/23/10.
+// Copyright 2010 Puppy Sound Software. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ObjectiveCKoansAppDelegate : NSObject <UIApplicationDelegate> {
+
+ UIWindow *window;
+ UINavigationController *navigationController;
+}
+
+@property (nonatomic, retain) IBOutlet UIWindow *window;
+@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
+
+@end
+
35 Classes/ObjectiveCKoansAppDelegate.m
@@ -0,0 +1,35 @@
+//
+// ObjectiveCKoansAppDelegate.m
+// ObjectiveCKoans
+//
+// Created by Joe Cannatti on 12/23/10.
+// Copyright 2010 Puppy Sound Software. All rights reserved.
+//
+
+#import "ObjectiveCKoansAppDelegate.h"
+
+@implementation ObjectiveCKoansAppDelegate
+
+@synthesize window;
+@synthesize navigationController;
+
+
+#pragma mark -
+#pragma mark Application lifecycle
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ // Add the navigation controller's view to the window and display.
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+- (void)dealloc {
+ [navigationController release];
+ [window release];
+ [super dealloc];
+}
+
+
+@end
+
22 Kiwi/KWAfterAllNode.h
@@ -0,0 +1,22 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlockNode.h"
+#import "KWExampleNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWAfterAllNode : KWBlockNode<KWExampleNode>
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)afterAllNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
30 Kiwi/KWAfterAllNode.m
@@ -0,0 +1,30 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWAfterAllNode.h"
+#import "KWExampleNodeVisitor.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWAfterAllNode
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)afterAllNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock {
+ return [[[self alloc] initWithCallSite:aCallSite description:nil block:aBlock] autorelease];
+}
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor {
+ [aVisitor visitAfterAllNode:self];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
22 Kiwi/KWAfterEachNode.h
@@ -0,0 +1,22 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlockNode.h"
+#import "KWExampleNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWAfterEachNode : KWBlockNode<KWExampleNode>
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)afterEachNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
30 Kiwi/KWAfterEachNode.m
@@ -0,0 +1,30 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWAfterEachNode.h"
+#import "KWExampleNodeVisitor.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWAfterEachNode
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)afterEachNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock {
+ return [[[self alloc] initWithCallSite:aCallSite description:nil block:aBlock] autorelease];
+}
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor {
+ [aVisitor visitAfterEachNode:self];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
23 Kiwi/KWBeBetweenMatcher.h
@@ -0,0 +1,23 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeBetweenMatcher : KWMatcher {
+@private
+ id lowerEndpoint;
+ id upperEndpoint;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+// TODO: 'and' below is a reserved word in C++
+- (void)beBetween:(id)aLowerEndpoint and:(id)anUpperEndpoint;
+- (void)beInTheIntervalFrom:(id)aLowerEndpoint to:(id)anUpperEndpoint;
+
+@end
79 Kiwi/KWBeBetweenMatcher.m
@@ -0,0 +1,79 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeBetweenMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWBeBetweenMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) id lowerEndpoint;
+@property (nonatomic, readwrite, retain) id upperEndpoint;
+
+@end
+
+@implementation KWBeBetweenMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [lowerEndpoint release];
+ [upperEndpoint release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize lowerEndpoint;
+@synthesize upperEndpoint;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"beBetween:and:", @"beInTheIntervalFrom:to:", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if (![self.subject respondsToSelector:@selector(compare:)])
+ [NSException raise:@"KWMatcherException" format:@"subject does not respond to -compare:"];
+
+ NSComparisonResult lowerResult = [self.subject compare:self.lowerEndpoint];
+ NSComparisonResult upperResult = [self.subject compare:self.upperEndpoint];
+ return (lowerResult == NSOrderedDescending || lowerResult == NSOrderedSame) &&
+ (upperResult == NSOrderedAscending || upperResult == NSOrderedSame);
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be in the interval [%@, %@], got %@",
+ [KWFormatter formatObject:self.lowerEndpoint],
+ [KWFormatter formatObject:self.upperEndpoint],
+ [KWFormatter formatObject:self.subject]];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beBetween:(id)aLowerEndpoint and:(id)anUpperEndpoint {
+ [self beInTheIntervalFrom:aLowerEndpoint to:anUpperEndpoint];
+}
+
+- (void)beInTheIntervalFrom:(id)aLowerEndpoint to:(id)anUpperEndpoint {
+ self.lowerEndpoint = aLowerEndpoint;
+ self.upperEndpoint = anUpperEndpoint;
+}
+
+@end
20 Kiwi/KWBeEmptyMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeEmptyMatcher : KWMatcher {
+@private
+ NSUInteger count;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beEmpty;
+
+@end
74 Kiwi/KWBeEmptyMatcher.m
@@ -0,0 +1,74 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeEmptyMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWBeEmptyMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite) NSUInteger count;
+
+@end
+
+@implementation KWBeEmptyMatcher
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize count;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"beEmpty"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if ([self.subject respondsToSelector:@selector(count)]) {
+ self.count = [self.subject count];
+ return self.count == 0;
+ }
+ else if ([self.subject respondsToSelector:@selector(length)]) {
+ self.count = [self.subject length];
+ return self.count == 0;
+ }
+
+ [NSException raise:@"KWMatcherException" format:@"subject does not respond to -count or -length"];
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)countPhrase {
+ if (self.count == 1)
+ return @"1 item";
+ else
+ return [NSString stringWithFormat:@"%u items", self.count];
+}
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be empty, got %@", [self countPhrase]];
+}
+
+- (NSString *)failureMessageForShouldNot {
+ return @"expected subject not to be empty";
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beEmpty {
+}
+
+@end
20 Kiwi/KWBeIdenticalToMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeIdenticalToMatcher : KWMatcher {
+@private
+ id otherSubject;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beIdenticalTo:(id)anObject;
+
+@end
72 Kiwi/KWBeIdenticalToMatcher.m
@@ -0,0 +1,72 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeIdenticalToMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWBeIdenticalToMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) id otherSubject;
+
+@end
+
+@implementation KWBeIdenticalToMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [otherSubject release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize otherSubject;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"beIdenticalTo:"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ return self.subject == self.otherSubject;
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be identical to %@ (%p), got %@ (%p)",
+ [KWFormatter formatObject:self.otherSubject],
+ self.otherSubject,
+ [KWFormatter formatObject:self.subject],
+ self.subject];
+}
+
+- (NSString *)failureMessageForShouldNot {
+ return [NSString stringWithFormat:@"expected subject not to be identical to %@ (%p)",
+ [KWFormatter formatObject:self.otherSubject],
+ self.otherSubject];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beIdenticalTo:(id)anObject {
+ self.otherSubject = anObject;
+}
+
+@end
20 Kiwi/KWBeKindOfClassMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeKindOfClassMatcher : KWMatcher {
+@private
+ Class targetClass;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beKindOfClass:(Class)aClass;
+
+@end
55 Kiwi/KWBeKindOfClassMatcher.m
@@ -0,0 +1,55 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeKindOfClassMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWBeKindOfClassMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, assign) Class targetClass;
+
+@end
+
+@implementation KWBeKindOfClassMatcher
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize targetClass;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"beKindOfClass:"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ return [self.subject isKindOfClass:self.targetClass];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be kind of %@",
+ NSStringFromClass(self.targetClass)];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beKindOfClass:(Class)aClass {
+ self.targetClass = aClass;
+}
+
+@end
20 Kiwi/KWBeMemberOfClassMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeMemberOfClassMatcher : KWMatcher {
+@private
+ Class targetClass;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beMemberOfClass:(Class)aClass;
+
+@end
55 Kiwi/KWBeMemberOfClassMatcher.m
@@ -0,0 +1,55 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeMemberOfClassMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWBeMemberOfClassMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, assign) Class targetClass;
+
+@end
+
+@implementation KWBeMemberOfClassMatcher
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize targetClass;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"beMemberOfClass:"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ return [self.subject isMemberOfClass:self.targetClass];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be member of %@",
+ NSStringFromClass(self.targetClass)];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beMemberOfClass:(Class)aClass {
+ self.targetClass = aClass;
+}
+
+@end
23 Kiwi/KWBeTrueMatcher.h
@@ -0,0 +1,23 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeTrueMatcher : KWMatcher {
+@private
+ BOOL expectedValue;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beTrue;
+- (void)beFalse;
+- (void)beYes;
+- (void)beNo;
+
+@end
69 Kiwi/KWBeTrueMatcher.m
@@ -0,0 +1,69 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeTrueMatcher.h"
+
+@interface KWBeTrueMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite) BOOL expectedValue;
+
+@end
+
+@implementation KWBeTrueMatcher
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize expectedValue;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"beTrue", @"beFalse", @"beYes", @"beNo", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if (![self.subject respondsToSelector:@selector(boolValue)])
+ [NSException raise:@"KWMatcherException" format:@"subject does not respond to -boolValue"];
+
+ return [self.subject boolValue] == self.expectedValue;
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be %@",
+ expectedValue ? @"true" : @"false"];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beTrue {
+ self.expectedValue = YES;
+}
+
+- (void)beFalse {
+ self.expectedValue = NO;
+}
+
+- (void)beYes {
+ self.expectedValue = YES;
+}
+
+- (void)beNo {
+ self.expectedValue = NO;
+}
+
+@end
22 Kiwi/KWBeWithinMatcher.h
@@ -0,0 +1,22 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeWithinMatcher : KWMatcher {
+@private
+ id distance;
+ id otherValue;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beWithin:(id)aDistance of:(id)aValue;
+- (void)equal:(double)aValue withDelta:(double)aDelta;
+
+@end
109 Kiwi/KWBeWithinMatcher.m
@@ -0,0 +1,109 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeWithinMatcher.h"
+#import "KWFormatter.h"
+#import "KWObjCUtilities.h"
+#import "KWValue.h"
+
+@interface KWBeWithinMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) id distance;
+@property (nonatomic, readwrite, retain) id otherValue;
+
+@end
+
+@implementation KWBeWithinMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [distance release];
+ [otherValue release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize distance;
+@synthesize otherValue;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"beWithin:of:", @"equal:withDelta:", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+// Evaluation is done by getting the underlying values as the widest data
+// types available.
+
+- (BOOL)evaluateForFloatingPoint {
+ double firstValue = [self.subject doubleValue];
+ double secondValue = [self.otherValue doubleValue];
+ double theDistance = [self.distance doubleValue];
+ double absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
+ return absoluteDifference <= theDistance;
+}
+
+- (BOOL)evaluateForUnsignedIntegral {
+ unsigned long long firstValue = [self.subject unsignedLongLongValue];
+ unsigned long long secondValue = [self.otherValue unsignedLongLongValue];
+ unsigned long long theDistance = [self.distance unsignedLongLongValue];
+ unsigned long long absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
+ return absoluteDifference <= theDistance;
+}
+
+- (BOOL)evaluateForSignedIntegral {
+ long long firstValue = [self.subject longLongValue];
+ long long secondValue = [self.otherValue longLongValue];
+ long long theDistance = [self.distance longLongValue];
+ long long absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
+ return absoluteDifference <= theDistance;
+}
+
+- (BOOL)evaluate {
+ const char *objCType = [self.subject objCType];
+
+ if (KWObjCTypeIsFloatingPoint(objCType))
+ return [self evaluateForFloatingPoint];
+ else if (KWObjCTypeIsUnsignedIntegral(objCType))
+ return [self evaluateForUnsignedIntegral];
+ else
+ return [self evaluateForSignedIntegral];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be within %@ of %@, got %@",
+ [KWFormatter formatObject:self.distance],
+ [KWFormatter formatObject:self.otherValue],
+ [KWFormatter formatObject:self.subject]];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beWithin:(id)aDistance of:(id)aValue {
+ self.distance = aDistance;
+ self.otherValue = aValue;
+}
+
+- (void)equal:(double)aValue withDelta:(double)aDelta {
+ [self beWithin:[KWValue valueWithDouble:aDelta] of:[KWValue valueWithDouble:aValue]];
+}
+
+@end
17 Kiwi/KWBeZeroMatcher.h
@@ -0,0 +1,17 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWBeZeroMatcher : KWMatcher
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beZero;
+
+@end
48 Kiwi/KWBeZeroMatcher.m
@@ -0,0 +1,48 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeZeroMatcher.h"
+#import "KWFormatter.h"
+#import "KWValue.h"
+
+@implementation KWBeZeroMatcher
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"beZero"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if (![self.subject respondsToSelector:@selector(boolValue)])
+ [NSException raise:@"KWMatcherException" format:@"subject does not respond to -numberValue"];
+
+ return [[self.subject numberValue] isEqualToNumber:[NSNumber numberWithInt:0]];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to be zero, got %@",
+ [KWFormatter formatObject:self.subject]];
+}
+
+- (NSString *)failureMessageForShouldNot {
+ return [NSString stringWithFormat:@"expected subject not to be zero"];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)beZero {
+}
+
+@end
22 Kiwi/KWBeforeAllNode.h
@@ -0,0 +1,22 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlockNode.h"
+#import "KWExampleNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWBeforeAllNode : KWBlockNode<KWExampleNode>
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)beforeAllNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
30 Kiwi/KWBeforeAllNode.m
@@ -0,0 +1,30 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeforeAllNode.h"
+#import "KWExampleNodeVisitor.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWBeforeAllNode
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)beforeAllNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock {
+ return [[[self alloc] initWithCallSite:aCallSite description:nil block:aBlock] autorelease];
+}
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor {
+ [aVisitor visitBeforeAllNode:self];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
22 Kiwi/KWBeforeEachNode.h
@@ -0,0 +1,22 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlockNode.h"
+#import "KWExampleNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWBeforeEachNode : KWBlockNode<KWExampleNode>
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)beforeEachNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
30 Kiwi/KWBeforeEachNode.m
@@ -0,0 +1,30 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBeforeEachNode.h"
+#import "KWExampleNodeVisitor.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWBeforeEachNode
+
+#pragma mark -
+#pragma mark Initializing
+
++ (id)beforeEachNodeWithCallSite:(KWCallSite *)aCallSite block:(KWVoidBlock)aBlock {
+ return [[[self alloc] initWithCallSite:aCallSite description:nil block:aBlock] autorelease];
+}
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor {
+ [aVisitor visitBeforeEachNode:self];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
37 Kiwi/KWBlock.h
@@ -0,0 +1,37 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+
+#if KW_BLOCKS_ENABLED
+
+typedef void (^KWVoidBlock)(void);
+
+@interface KWBlock : NSObject {
+@private
+ KWVoidBlock block;
+}
+
+#pragma mark -
+#pragma mark Initializing
+- (id)initWithBlock:(KWVoidBlock)aBlock;
+
++ (id)blockWithBlock:(KWVoidBlock)aBlock;
+
+#pragma mark -
+#pragma mark Calling Blocks
+
+- (void)call;
+
+@end
+
+#pragma mark -
+#pragma mark Creating Blocks
+
+KWBlock *theBlock(KWVoidBlock aBlock);
+KWBlock *lambda(KWVoidBlock aBlock);
+
+#endif // #if KW_BLOCKS_ENABLED
67 Kiwi/KWBlock.m
@@ -0,0 +1,67 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBlock.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWBlock()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readonly, assign) KWVoidBlock block;
+
+@end
+
+@implementation KWBlock
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithBlock:(KWVoidBlock)aBlock {
+ if ((self = [super init])) {
+ block = Block_copy(aBlock);
+ }
+
+ return self;
+}
+
++ (id)blockWithBlock:(KWVoidBlock)aBlock {
+ return [[[self alloc] initWithBlock:aBlock] autorelease];
+}
+
+- (void)dealloc {
+ Block_release(block);
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize block;
+
+#pragma mark -
+#pragma mark Calling Blocks
+
+- (void)call {
+ block();
+}
+
+@end
+
+#pragma mark -
+#pragma mark Creating Blocks
+
+KWBlock *theBlock(KWVoidBlock aBlock) {
+ return lambda(aBlock);
+}
+
+KWBlock *lambda(KWVoidBlock aBlock) {
+ return [KWBlock blockWithBlock:aBlock];
+}
+
+#endif // #if KW_BLOCKS_ENABLED
43 Kiwi/KWBlockNode.h
@@ -0,0 +1,43 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlock.h"
+
+#if KW_BLOCKS_ENABLED
+
+@class KWCallSite;
+
+@interface KWBlockNode : NSObject {
+@private
+ KWCallSite *callSite;
+ NSString *description;
+ KWVoidBlock block;
+}
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription block:(KWVoidBlock)aBlock;
+
+#pragma mark -
+#pragma mark Getting Call Sites
+
+@property (nonatomic, readonly) KWCallSite *callSite;
+
+#pragma mark -
+#pragma mark Getting Descriptions
+
+@property (nonatomic, readonly) NSString *description;
+
+#pragma mark -
+#pragma mark Getting Blocks
+
+@property (nonatomic, readonly) KWVoidBlock block;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
55 Kiwi/KWBlockNode.m
@@ -0,0 +1,55 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBlockNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWBlockNode
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription block:(KWVoidBlock)aBlock{
+ if ((self = [super init])) {
+ callSite = [aCallSite retain];
+ description = [aDescription copy];
+
+ if (aBlock != nil)
+ block = Block_copy(aBlock);
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [callSite release];
+ [description release];
+
+ if (block != nil)
+ Block_release(block);
+
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Getting Call Sites
+
+@synthesize callSite;
+
+#pragma mark -
+#pragma mark Getting Descriptions
+
+@synthesize description;
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+@synthesize block;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
28 Kiwi/KWBlockRaiseMatcher.h
@@ -0,0 +1,28 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWBlockRaiseMatcher : KWMatcher {
+@private
+ NSException *exception;
+ NSException *actualException;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)raise;
+- (void)raiseWithName:(NSString *)aName;
+- (void)raiseWithReason:(NSString *)aReason;
+- (void)raiseWithName:(NSString *)aName reason:(NSString *)aReason;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
125 Kiwi/KWBlockRaiseMatcher.m
@@ -0,0 +1,125 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWBlockRaiseMatcher.h"
+#import "KWBlock.h"
+
+#if KW_BLOCKS_ENABLED
+
+@interface KWBlockRaiseMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) NSException *exception;
+@property (nonatomic, readwrite, retain) NSException *actualException;
+
+@end
+
+@implementation KWBlockRaiseMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [exception release];
+ [actualException release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize exception;
+@synthesize actualException;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"raise",
+ @"raiseWithName:",
+ @"raiseWithReason:",
+ @"raiseWithName:reason:", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if (![self.subject isKindOfClass:[KWBlock class]])
+ [NSException raise:@"KWMatcherException" format:@"subject must be a KWBlock"];
+
+ @try {
+ [self.subject call];
+ } @catch (NSException *anException) {
+ self.actualException = anException;
+
+ if ([self.exception name] != nil && ![[self.exception name] isEqualToString:[anException name]])
+ return NO;
+
+ if ([self.exception reason] != nil && ![[self.exception reason] isEqualToString:[anException reason]])
+ return NO;
+
+ return YES;
+ }
+
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
++ (NSString *)exceptionPhraseWithException:(NSException *)anException {
+ if (anException == nil)
+ return @"nothing";
+
+ NSString *namePhrase = nil;
+
+ if ([anException name] == nil)
+ namePhrase = @"exception";
+ else
+ namePhrase = [anException name];
+
+ if ([anException reason] == nil)
+ return namePhrase;
+
+ return [NSString stringWithFormat:@"%@ \"%@\"", namePhrase, [anException reason]];
+}
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected %@, but %@ raised",
+ [[self class] exceptionPhraseWithException:self.exception],
+ [[self class] exceptionPhraseWithException:self.actualException]];
+}
+
+- (NSString *)failureMessageForShouldNot {
+ return [NSString stringWithFormat:@"expected %@ not to be raised",
+ [[self class] exceptionPhraseWithException:self.actualException]];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)raise {
+ [self raiseWithName:nil reason:nil];
+}
+
+- (void)raiseWithName:(NSString *)aName {
+ [self raiseWithName:aName reason:nil];
+}
+
+- (void)raiseWithReason:(NSString *)aReason {
+ [self raiseWithName:nil reason:aReason];
+}
+
+- (void)raiseWithName:(NSString *)aName reason:(NSString *)aReason {
+ self.exception = [NSException exceptionWithName:aName reason:aReason userInfo:nil];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
33 Kiwi/KWCallSite.h
@@ -0,0 +1,33 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+
+@interface KWCallSite : NSObject {
+@private
+ NSString *filename;
+ NSUInteger lineNumber;
+}
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithFilename:(NSString *)aFilename lineNumber:(NSUInteger)aLineNumber;
+
++ (id)callSiteWithFilename:(NSString *)aFilename lineNumber:(NSUInteger)aLineNumber;
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readonly, copy) NSString *filename;
+@property (nonatomic, readonly) NSUInteger lineNumber;
+
+#pragma mark -
+#pragma mark Identifying and Comparing
+
+- (BOOL)isEqualToCallSite:(KWCallSite *)aCallSite;
+
+@end
56 Kiwi/KWCallSite.m
@@ -0,0 +1,56 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWCallSite.h"
+
+@implementation KWCallSite
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithFilename:(NSString *)aFilename lineNumber:(NSUInteger)aLineNumber {
+ if ((self = [super init])) {
+ filename = [aFilename copy];
+ lineNumber = aLineNumber;
+ }
+
+ return self;
+}
+
++ (id)callSiteWithFilename:(NSString *)aFilename lineNumber:(NSUInteger)aLineNumber {
+ return [[[self alloc] initWithFilename:aFilename lineNumber:aLineNumber] autorelease];
+}
+
+- (void)dealloc {
+ [filename release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Accessing Call Site Properties
+
+@synthesize filename;
+@synthesize lineNumber;
+
+#pragma mark -
+#pragma mark Identifying and Comparing
+
+- (NSUInteger)hash {
+ return [[NSString stringWithFormat:@"%@%u", self.filename, self.lineNumber] hash];
+}
+
+- (BOOL)isEqual:(id)anObject {
+ if (![anObject isKindOfClass:[KWCallSite class]])
+ return NO;
+
+ return [self isEqualToCallSite:anObject];
+}
+
+- (BOOL)isEqualToCallSite:(KWCallSite *)aCallSite {
+ return [self.filename isEqualToString:aCallSite.filename] && (self.lineNumber == aCallSite.lineNumber);
+}
+
+@end
20 Kiwi/KWConformToProtocolMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWConformToProtocolMatcher : KWMatcher {
+@private
+ Protocol *protocol;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)conformToProtocol:(Protocol *)aProtocol;
+
+@end
55 Kiwi/KWConformToProtocolMatcher.m
@@ -0,0 +1,55 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWConformToProtocolMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWConformToProtocolMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, assign) Protocol *protocol;
+
+@end
+
+@implementation KWConformToProtocolMatcher
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize protocol;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObject:@"conformToProtocol:"];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ return [self.subject conformsToProtocol:self.protocol];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to conform to %@",
+ NSStringFromProtocol(self.protocol)];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)conformToProtocol:(Protocol *)aProtocol {
+ self.protocol = aProtocol;
+}
+
+@end
31 Kiwi/KWContainMatcher.h
@@ -0,0 +1,31 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+#import "KWMatchVerifier.h"
+
+@interface KWContainMatcher : KWMatcher {
+@private
+ NSArray *objects;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)contain:(id)anObject;
+- (void)containObjectsInArray:(NSArray *)anArray;
+
+@end
+
+@interface KWMatchVerifier(KWContainMatcherAdditions)
+
+#pragma mark -
+#pragma mark Verifying
+
+- (void)containObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
+
+@end
104 Kiwi/KWContainMatcher.m
@@ -0,0 +1,104 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWContainMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWContainMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) id objects;
+
+@end
+
+@implementation KWContainMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [objects release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize objects;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"contain:", @"containObjectsInArray:", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ if (![self.subject respondsToSelector:@selector(containsObject:)])
+ [NSException raise:@"KWMatcherException" format:@"subject does not respond to -containsObject:"];
+
+ for (id object in self.objects) {
+ if (![self.subject containsObject:object])
+ return NO;
+ }
+
+ return YES;
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)objectsPhrase {
+ if ([self.objects count] == 1)
+ return [KWFormatter formatObject:[self.objects objectAtIndex:0]];
+
+ return [KWFormatter formatObject:self.objects];
+}
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to contain %@", [self objectsPhrase]];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)contain:(id)anObject {
+ self.objects = [NSArray arrayWithObject:anObject];
+}
+
+- (void)containObjectsInArray:(NSArray *)anArray {
+ self.objects = anArray;
+}
+
+@end
+
+@implementation KWMatchVerifier(KWContainMatcherAdditions)
+
+#pragma mark -
+#pragma mark Verifying
+
+- (void)containObjects:(id)firstObject, ... {
+ NSMutableArray *objects = [[NSMutableArray alloc] init];
+
+ va_list argumentList;
+ va_start(argumentList, firstObject);
+ id object = firstObject;
+
+ while (object != nil) {
+ [objects addObject:object];
+ object = va_arg(argumentList, id);
+ }
+
+ va_end(argumentList);
+ [(id)self containObjectsInArray:objects];
+}
+
+@end
71 Kiwi/KWContextNode.h
@@ -0,0 +1,71 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWExampleNode.h"
+
+#if KW_BLOCKS_ENABLED
+
+@class KWAfterAllNode;
+@class KWAfterEachNode;
+@class KWBeforeAllNode;
+@class KWBeforeEachNode;
+@class KWCallSite;
+@class KWItNode;
+@class KWPendingNode;
+@class KWRegisterMatchersNode;
+
+@interface KWContextNode : NSObject<KWExampleNode> {
+@private
+ KWCallSite *callSite;
+ NSString *description;
+ KWRegisterMatchersNode *registerMatchersNode;
+ KWBeforeAllNode *beforeAllNode;
+ KWAfterAllNode *afterAllNode;
+ KWBeforeEachNode *beforeEachNode;
+ KWAfterEachNode *afterEachNode;
+ NSMutableArray *nodes;
+}
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription;
+
++ (id)contextNodeWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription;
+
+#pragma mark -
+#pragma mark Getting Call Sites
+
+@property (nonatomic, readonly) KWCallSite *callSite;
+
+#pragma mark -
+#pragma mark Getting Descriptions
+
+@property (nonatomic, readonly) NSString *description;
+
+#pragma mark -
+#pragma mark Managing Nodes
+
+@property (nonatomic, readwrite, retain) KWRegisterMatchersNode *registerMatchersNode;
+@property (nonatomic, readwrite, retain) KWBeforeAllNode *beforeAllNode;
+@property (nonatomic, readwrite, retain) KWAfterAllNode *afterAllNode;
+@property (nonatomic, readwrite, retain) KWBeforeEachNode *beforeEachNode;
+@property (nonatomic, readwrite, retain) KWAfterEachNode *afterEachNode;
+@property (nonatomic, readonly) NSArray *nodes;
+
+- (void)addContextNode:(KWContextNode *)aNode;
+- (void)addItNode:(KWItNode *)aNode;
+- (void)addPendingNode:(KWPendingNode *)aNode;
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor;
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
105 Kiwi/KWContextNode.m
@@ -0,0 +1,105 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWContextNode.h"
+#import "KWExampleNodeVisitor.h"
+
+#if KW_BLOCKS_ENABLED
+
+@implementation KWContextNode
+
+#pragma mark -
+#pragma mark Initializing
+
+- (id)initWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription {
+ if ((self = [super init])) {
+ callSite = [aCallSite retain];
+ description = [aDescription copy];
+ nodes = [[NSMutableArray alloc] init];
+ }
+
+ return self;
+}
+
++ (id)contextNodeWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription {
+ return [[[self alloc] initWithCallSite:aCallSite description:aDescription] autorelease];
+}
+
+- (void)dealloc {
+ [callSite release];
+ [description release];
+ [registerMatchersNode release];
+ [beforeAllNode release];
+ [afterAllNode release];
+ [beforeEachNode release];
+ [afterEachNode release];
+ [nodes release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Getting Call Sites
+
+@synthesize callSite;
+
+#pragma mark -
+#pragma mark Getting Descriptions
+
+@synthesize description;
+
+#pragma mark -
+#pragma mark Managing Nodes
+
+@synthesize registerMatchersNode;
+@synthesize beforeAllNode;
+@synthesize afterAllNode;
+@synthesize beforeEachNode;
+@synthesize afterEachNode;
+@synthesize nodes;
+
+- (void)addContextNode:(KWContextNode *)aNode {
+ [(NSMutableArray *)self.nodes addObject:aNode];
+}
+
+- (void)setRegisterMatchersNode:(KWRegisterMatchersNode *)aNode {
+ if (self.registerMatchersNode != nil)
+ [NSException raise:@"KWContextNodeException" format:@"a register matchers node already exists"];
+
+ registerMatchersNode = [aNode retain];
+}
+
+- (void)setBeforeEachNode:(KWBeforeEachNode *)aNode {
+ if (self.beforeEachNode != nil)
+ [NSException raise:@"KWContextNodeException" format:@"a before each node already exists"];
+
+ beforeEachNode = [aNode retain];
+}
+
+- (void)setAfterEachNode:(KWAfterEachNode *)aNode {
+ if (self.afterEachNode != nil)
+ [NSException raise:@"KWContextNodeException" format:@"an after each node already exists"];
+
+ afterEachNode = [aNode retain];
+}
+
+- (void)addItNode:(KWItNode *)aNode {
+ [(NSMutableArray *)self.nodes addObject:aNode];
+}
+
+- (void)addPendingNode:(KWPendingNode *)aNode {
+ [(NSMutableArray *)self.nodes addObject:aNode];
+}
+
+#pragma mark -
+#pragma mark Accepting Visitors
+
+- (void)acceptExampleNodeVisitor:(id<KWExampleNodeVisitor>)aVisitor {
+ [aVisitor visitContextNode:self];
+}
+
+@end
+
+#endif // #if KW_BLOCKS_ENABLED
15 Kiwi/KWCountType.h
@@ -0,0 +1,15 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+
+enum {
+ KWCountTypeExact,
+ KWCountTypeAtLeast,
+ KWCountTypeAtMost
+};
+
+typedef NSUInteger KWCountType;
17 Kiwi/KWDeviceInfo.h
@@ -0,0 +1,17 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+
+@interface KWDeviceInfo : NSObject
+
+#pragma mark -
+#pragma mark Getting the Device Type
+
++ (BOOL)isSimulator;
++ (BOOL)isPhysical;
+
+@end
33 Kiwi/KWDeviceInfo.m
@@ -0,0 +1,33 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWDeviceInfo.h"
+
+#if TARGET_IPHONE_SIMULATOR
+
+#import <UIKit/UIKit.h>
+
+#endif // #if TARGET_IPHONE_SIMULATOR
+
+@implementation KWDeviceInfo
+
+#pragma mark -
+#pragma mark Getting the Device Type
+
++ (BOOL)isSimulator {
+#if TARGET_IPHONE_SIMULATOR
+ NSString *model = [[UIDevice currentDevice] model];
+ return [model hasSuffix:@" Simulator"];
+#else
+ return NO;
+#endif // #if TARGET_IPHONE_SIMULATOR
+}
+
++ (BOOL)isPhysical {
+ return ![self isSimulator];
+}
+
+@end
20 Kiwi/KWEqualMatcher.h
@@ -0,0 +1,20 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWMatcher.h"
+
+@interface KWEqualMatcher : KWMatcher {
+@private
+ id otherSubject;
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)equal:(id)anObject;
+
+@end
69 Kiwi/KWEqualMatcher.m
@@ -0,0 +1,69 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KWEqualMatcher.h"
+#import "KWFormatter.h"
+
+@interface KWEqualMatcher()
+
+#pragma mark -
+#pragma mark Properties
+
+@property (nonatomic, readwrite, retain) id otherSubject;
+
+@end
+
+@implementation KWEqualMatcher
+
+#pragma mark -
+#pragma mark Initializing
+
+- (void)dealloc {
+ [otherSubject release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Properties
+
+@synthesize otherSubject;
+
+#pragma mark -
+#pragma mark Getting Matcher Strings
+
++ (NSArray *)matcherStrings {
+ return [NSArray arrayWithObjects:@"equal:", nil];
+}
+
+#pragma mark -
+#pragma mark Matching
+
+- (BOOL)evaluate {
+ return [self.subject isEqual:self.otherSubject];
+}
+
+#pragma mark -
+#pragma mark Getting Failure Messages
+
+- (NSString *)failureMessageForShould {
+ return [NSString stringWithFormat:@"expected subject to equal %@, got %@",
+ [KWFormatter formatObject:self.otherSubject],
+ [KWFormatter formatObject:self.subject]];
+}
+
+- (NSString *)failureMessageForShouldNot {
+ return [NSString stringWithFormat:@"expected subject not to equal %@",
+ [KWFormatter formatObject:self.otherSubject]];
+}
+
+#pragma mark -
+#pragma mark Configuring Matchers
+
+- (void)equal:(id)anObject {
+ self.otherSubject = anObject;
+}
+
+@end
37 Kiwi/KWExampleGroup.h
@@ -0,0 +1,37 @@
+//
+// Licensed under the terms in License.txt
+//
+// Copyright 2010 Allen Ding. All rights reserved.
+//
+
+#import "KiwiConfiguration.h"
+#import "KWBlock.h"
+
+#if KW_BLOCKS_ENABLED
+
+@class KWCallSite;
+
+#pragma mark -
+#pragma mark Building Example Groups
+
+void describe(NSString *aDescription, KWVoidBlock aBlock);
+void context(NSString *aDescription, KWVoidBlock aBlock);
+void registerMatchers(NSString *aNamespacePrefix);
+void beforeAll(KWVoidBlock aBlock);
+void afterAll(KWVoidBlock aBlock);
+void beforeEach(KWVoidBlock aBlock);
+void afterEach(KWVoidBlock aBlock);
+void it(NSString *aDescription, KWVoidBlock aBlock);
+void pending(NSString *aDescription, KWVoidBlock ignoredBlock);
+
+void describeWithCallSite(KWCallSite *aCallSite, NSString *aDescription, KWVoidBlock aBlock);
+void contextWithCallSite(KWCallSite *aCallSite, NSString *aDescription, KWVoidBlock aBlock);
+void registerMatchersWithCallSite(KWCallSite *aCallSite, NSString *aNamespacePrefix);
+<