KWExampleSuiteBuilder.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //
  2. // Licensed under the terms in License.txt
  3. //
  4. // Copyright 2010 Allen Ding. All rights reserved.
  5. //
  6. #import "KWExampleSuiteBuilder.h"
  7. #import "KWAfterAllNode.h"
  8. #import "KWAfterEachNode.h"
  9. #import "KWBeforeAllNode.h"
  10. #import "KWBeforeEachNode.h"
  11. #import "KWLetNode.h"
  12. #import "KWCallSite.h"
  13. #import "KWContextNode.h"
  14. #import "KWExample.h"
  15. #import "KWExampleSuite.h"
  16. #import "KWItNode.h"
  17. #import "KWPendingNode.h"
  18. #import "KWRegisterMatchersNode.h"
  19. #import "KWSymbolicator.h"
  20. static NSString * const KWExampleSuiteBuilderException = @"KWExampleSuiteBuilderException";
  21. @interface KWExampleSuiteBuilder()
  22. #pragma mark - Building Example Groups
  23. @property (nonatomic, strong) KWExampleSuite *currentExampleSuite;
  24. @property (nonatomic, readonly) NSMutableArray *contextNodeStack;
  25. @property (nonatomic, strong) NSMutableSet *suites;
  26. @property (nonatomic, assign) BOOL focusedContextNode;
  27. @property (nonatomic, assign) BOOL focusedItNode;
  28. @end
  29. @implementation KWExampleSuiteBuilder
  30. #pragma mark - Initializing
  31. - (id)init {
  32. self = [super init];
  33. if (self) {
  34. _contextNodeStack = [[NSMutableArray alloc] init];
  35. _suites = [[NSMutableSet alloc] init];
  36. [self focusWithURI:[[[NSProcessInfo processInfo] environment] objectForKey:@"KW_SPEC"]];
  37. }
  38. return self;
  39. }
  40. + (id)sharedExampleSuiteBuilder {
  41. static KWExampleSuiteBuilder *sharedExampleSuiteBuilder = nil;
  42. static dispatch_once_t onceToken;
  43. dispatch_once(&onceToken, ^{
  44. sharedExampleSuiteBuilder = [self new];
  45. });
  46. return sharedExampleSuiteBuilder;
  47. }
  48. #pragma mark - Focus
  49. - (void)focusWithURI:(NSString *)nodeUrl {
  50. NSArray *focusInfo = [nodeUrl componentsSeparatedByString:@":"];
  51. if (!focusInfo || focusInfo.count != 2)
  52. return;
  53. self.focusedCallSite = [KWCallSite callSiteWithFilename:focusInfo[0] lineNumber:[focusInfo[1] intValue]];
  54. }
  55. - (void)setFocusedCallSite:(KWCallSite *)aFocusedCallSite {
  56. _focusedCallSite = aFocusedCallSite;
  57. self.focusedItNode = NO;
  58. self.focusedContextNode = NO;
  59. }
  60. - (BOOL)isFocused {
  61. return self.focusedCallSite != nil;
  62. }
  63. - (BOOL)foundFocus {
  64. return self.focusedContextNode || self.focusedItNode;
  65. }
  66. #pragma mark - Building Example Groups
  67. - (BOOL)isBuildingExampleSuite {
  68. return [self.contextNodeStack count] > 0;
  69. }
  70. - (KWExampleSuite *)buildExampleSuite:(void (^)(void))buildingBlock
  71. {
  72. KWContextNode *rootNode = [KWContextNode contextNodeWithCallSite:nil parentContext:nil description:nil];
  73. self.currentExampleSuite = [[KWExampleSuite alloc] initWithRootNode:rootNode];
  74. [self.suites addObject:self.currentExampleSuite];
  75. [self.contextNodeStack addObject:rootNode];
  76. buildingBlock();
  77. [self.contextNodeStack removeAllObjects];
  78. return self.currentExampleSuite;
  79. }
  80. - (void)pushContextNodeWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription {
  81. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  82. KWContextNode *node = [KWContextNode contextNodeWithCallSite:aCallSite parentContext:contextNode description:aDescription];
  83. if (self.isFocused)
  84. node.isFocused = [self shouldFocusContextNodeWithCallSite:aCallSite parentNode:contextNode];
  85. [contextNode addContextNode:node];
  86. [self.contextNodeStack addObject:node];
  87. }
  88. - (BOOL)shouldFocusContextNodeWithCallSite:(KWCallSite *)aCallSite parentNode:(KWContextNode *)parentNode {
  89. if (parentNode.isFocused)
  90. return YES;
  91. if ([aCallSite isEqualToCallSite:self.focusedCallSite]) {
  92. self.focusedContextNode = YES;
  93. return YES;
  94. }
  95. return NO;
  96. }
  97. - (void)popContextNode {
  98. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  99. [self.currentExampleSuite markLastExampleAsLastInContext:contextNode];
  100. if ([self.contextNodeStack count] == 1) {
  101. [NSException raise:KWExampleSuiteBuilderException
  102. format:@"there is no open context to pop"];
  103. }
  104. [self.contextNodeStack removeLastObject];
  105. }
  106. - (void)setRegisterMatchersNodeWithCallSite:(KWCallSite *)aCallSite namespacePrefix:(NSString *)aNamespacePrefix {
  107. [self raiseIfExampleGroupNotStarted];
  108. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  109. KWRegisterMatchersNode *registerMatchersNode = [KWRegisterMatchersNode registerMatchersNodeWithCallSite:aCallSite namespacePrefix:aNamespacePrefix];
  110. [contextNode addRegisterMatchersNode:registerMatchersNode];
  111. }
  112. - (void)setBeforeAllNodeWithCallSite:(KWCallSite *)aCallSite block:(void (^)(void))block {
  113. [self raiseIfExampleGroupNotStarted];
  114. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  115. KWBeforeAllNode *beforeAllNode = [KWBeforeAllNode beforeAllNodeWithCallSite:aCallSite block:block];
  116. [contextNode setBeforeAllNode:beforeAllNode];
  117. }
  118. - (void)setAfterAllNodeWithCallSite:(KWCallSite *)aCallSite block:(void (^)(void))block {
  119. [self raiseIfExampleGroupNotStarted];
  120. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  121. KWAfterAllNode *afterAllNode = [KWAfterAllNode afterAllNodeWithCallSite:aCallSite block:block];
  122. [contextNode setAfterAllNode:afterAllNode];
  123. }
  124. - (void)setBeforeEachNodeWithCallSite:(KWCallSite *)aCallSite block:(void (^)(void))block {
  125. [self raiseIfExampleGroupNotStarted];
  126. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  127. KWBeforeEachNode *beforeEachNode = [KWBeforeEachNode beforeEachNodeWithCallSite:aCallSite block:block];
  128. [contextNode setBeforeEachNode:beforeEachNode];
  129. }
  130. - (void)setAfterEachNodeWithCallSite:(KWCallSite *)aCallSite block:(void (^)(void))block {
  131. [self raiseIfExampleGroupNotStarted];
  132. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  133. KWAfterEachNode *afterEachNode = [KWAfterEachNode afterEachNodeWithCallSite:aCallSite block:block];
  134. [contextNode setAfterEachNode:afterEachNode];
  135. }
  136. - (void)addLetNodeWithCallSite:(KWCallSite *)aCallSite objectRef:(__autoreleasing id *)anObjectRef symbolName:(NSString *)aSymbolName block:(id (^)(void))block {
  137. [self raiseIfExampleGroupNotStarted];
  138. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  139. [contextNode addLetNode:[KWLetNode letNodeWithSymbolName:aSymbolName objectRef:anObjectRef block:block]];
  140. }
  141. - (void)addItNodeWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription block:(void (^)(void))block {
  142. [self raiseIfExampleGroupNotStarted];
  143. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  144. if (self.isFocused && ![self shouldAddItNodeWithCallSite:aCallSite toContextNode:contextNode])
  145. return;
  146. KWItNode* itNode = [KWItNode itNodeWithCallSite:aCallSite description:aDescription context:contextNode block:block];
  147. [contextNode addItNode:itNode];
  148. KWExample *example = [[KWExample alloc] initWithExampleNode:itNode];
  149. [self.currentExampleSuite addExample:example];
  150. }
  151. - (BOOL)shouldAddItNodeWithCallSite:(KWCallSite *)aCallSite toContextNode:(KWContextNode *)contextNode {
  152. if (contextNode.isFocused)
  153. return YES;
  154. if([aCallSite isEqualToCallSite:self.focusedCallSite]){
  155. self.focusedItNode = YES;
  156. return YES;
  157. }
  158. return NO;
  159. }
  160. - (void)addPendingNodeWithCallSite:(KWCallSite *)aCallSite description:(NSString *)aDescription {
  161. [self raiseIfExampleGroupNotStarted];
  162. KWContextNode *contextNode = [self.contextNodeStack lastObject];
  163. KWPendingNode *pendingNode = [KWPendingNode pendingNodeWithCallSite:aCallSite context:contextNode description:aDescription];
  164. [contextNode addPendingNode:pendingNode];
  165. KWExample *example = [[KWExample alloc] initWithExampleNode:pendingNode];
  166. [self.currentExampleSuite addExample:example];
  167. }
  168. - (void)raiseIfExampleGroupNotStarted {
  169. if ([self.contextNodeStack count] == 0) {
  170. [NSException raise:KWExampleSuiteBuilderException
  171. format:@"an example group has not been started"];
  172. }
  173. }
  174. @end