Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invariant support [#289, #81557010] #294

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Source/CDRExample.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ - (void)dealloc {
[super dealloc];
}

- (id)copy {
CDRExample* example = [[CDRExample alloc] initWithText:text_ andBlock:block_];
example.focused = self.focused;
return example;
}

#pragma mark CDRExampleBase
- (CDRExampleState)state {
return state_;
Expand Down
60 changes: 59 additions & 1 deletion Source/CDRExampleGroup.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ - (id)initWithText:(NSString *)text isRoot:(BOOL)isRoot {
beforeBlocks_ = [[NSMutableArray alloc] init];
examples_ = [[NSMutableArray alloc] init];
afterBlocks_ = [[NSMutableArray alloc] init];
invariants_ = [[NSMutableArray alloc] init];
isRoot_ = isRoot;
}
return self;
Expand All @@ -33,6 +34,7 @@ - (void)dealloc {
[afterBlocks_ release];
[examples_ release];
[beforeBlocks_ release];
[invariants_ release];
self.subjectActionBlock = nil;
[super dealloc];
}
Expand Down Expand Up @@ -74,6 +76,13 @@ - (void)addAfter:(CDRSpecBlock)block {
[blockCopy release];
}

- (void)addInvariant:(CDRExampleBase *)inv {
CDRExampleBase * invCopy = [inv copy];
invCopy.parent = self;
[invariants_ addObject: invCopy];
[invCopy release];
}

#pragma mark CDRExampleBase
- (CDRExampleState)state {
if (0 == [examples_ count]) {
Expand All @@ -96,7 +105,10 @@ - (float)progress {
for (CDRExampleBase *example in examples_) {
aggregateProgress += [example progress];
}
return aggregateProgress / [examples_ count];
for (CDRExampleBase *example in invariants_) {
aggregateProgress += [example progress];
}
return aggregateProgress / ([examples_ count] + [invariants_ count]);
}


Expand All @@ -107,12 +119,17 @@ - (void)runWithDispatcher:(CDRReportDispatcher *)dispatcher {
userInfo:nil] raise];
}

[self collectInvariants];

[dispatcher runWillStartExampleGroup:self];
[startDate_ release];
startDate_ = [[NSDate alloc] init];

[self startObservingExamples];
[examples_ makeObjectsPerformSelector:@selector(runWithDispatcher:) withObject:dispatcher];
if ([examples_ count] > 0) {
[invariants_ makeObjectsPerformSelector:@selector(runWithDispatcher:) withObject:dispatcher];
}
[self stopObservingExamples];

[endDate_ release];
Expand All @@ -121,13 +138,19 @@ - (void)runWithDispatcher:(CDRReportDispatcher *)dispatcher {

[beforeBlocks_ release]; beforeBlocks_ = nil;
[afterBlocks_ release]; afterBlocks_ = nil;
[invariants_ release]; invariants_ = nil;
self.subjectActionBlock = nil;
}

- (BOOL)hasFocusedExamples {
if (self.isFocused) {
return YES;

} else if ([self hasFocusedInvariant]) {
[self forceFocus];
return YES;
}

for (CDRExampleBase *example in examples_) {
if ([example hasFocusedExamples]) {
return YES;
Expand Down Expand Up @@ -173,12 +196,47 @@ - (void)startObservingExamples {
for (id example in examples_) {
[example addObserver:self forKeyPath:@"state" options:0 context:NULL];
}
for (id example in invariants_) {
[example addObserver:self forKeyPath:@"state" options:0 context:NULL];
}
}

- (void)stopObservingExamples {
for (id example in examples_) {
[example removeObserver:self forKeyPath:@"state"];
}
for (id example in invariants_) {
[example removeObserver:self forKeyPath:@"state"];
}
}

- (void)collectInvariants {
//Because of recursive call order for runWithDispatcher: all grandparent invariants have been propagated down to parent by the time [self collectInvariants] is called
//So no recursive call is necessary
if ([self.parent isKindOfClass:[CDRExampleGroup class]]) {
for (id inv in ((CDRExampleGroup*)self.parent)->invariants_) {
[self addInvariant: ((CDRExampleBase*)inv)];
}
}
}

- (BOOL)hasFocusedInvariant {
for (CDRExampleBase *example in invariants_) {
if ([example isFocused]) {
return YES;
}
}
return NO;
}

//An invariant is focused, so we need to propagate focus *down* the tree
- (void)forceFocus {
self.focused = YES;
for (id child in examples_) {
if ([child isKindOfClass:[CDRExampleGroup class]]) {
[child forceFocus];
}
}
}

@end
25 changes: 25 additions & 0 deletions Source/CDRSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ void afterEach(CDRSpecBlock block) {
#define with_stack_address(b) \
((b.stackAddress = CDRCallerStackAddress()), b)

CDRExample * invariant(NSString *text, CDRSpecBlock block) {
NSString * invName = [NSString stringWithFormat:@"should always %@", text];
CDRExample * example = [CDRExample exampleWithText:invName andBlock:block];
[CDR_currentSpec.currentGroup addInvariant:example];
return with_stack_address(example);
}

CDRExample* (*it_should_always)(NSString *, CDRSpecBlock) = &invariant;

CDRExampleGroup * describe(NSString *text, CDRSpecBlock block) {
CDRExampleGroup *group = nil;
if (block) {
Expand Down Expand Up @@ -66,6 +75,14 @@ void subjectAction(CDRSpecBlock block) {
return with_stack_address(example);
}

CDRExample * xinvariant(NSString *text, CDRSpecBlock block) {
NSString * invName = [NSString stringWithFormat:@"should always %@", text];
CDRExample *example = [CDRExample exampleWithText:invName andBlock:PENDING];
return with_stack_address(example);
}

CDRExample* (*xit_should_always)(NSString *, CDRSpecBlock) = &xinvariant;

#pragma mark - Focused

CDRExampleGroup * fdescribe(NSString *text, CDRSpecBlock block) {
Expand All @@ -82,6 +99,14 @@ void subjectAction(CDRSpecBlock block) {
return with_stack_address(example);
}

CDRExample * finvariant(NSString *text, CDRSpecBlock block) {
CDRExample *example = invariant(text, block);
example.focused = YES;
return with_stack_address(example);
}

CDRExample * (*fit_should_always)(NSString *, CDRSpecBlock) = &finvariant;

void fail(NSString *reason) {
[[CDRSpecFailure specFailureWithReason:[NSString stringWithFormat:@"Failure: %@", reason]] raise];
}
Expand Down
3 changes: 2 additions & 1 deletion Source/Headers/CDRExampleGroup.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import "CDRExampleBase.h"

@interface CDRExampleGroup : CDRExampleBase <CDRExampleParent> {
NSMutableArray *beforeBlocks_, *examples_, *afterBlocks_;
NSMutableArray *beforeBlocks_, *examples_, *afterBlocks_, *invariants_;
BOOL isRoot_;
CDRSpecBlock subjectActionBlock_;
}
Expand All @@ -15,5 +15,6 @@
- (void)add:(CDRExampleBase *)example;
- (void)addBefore:(CDRSpecBlock)block;
- (void)addAfter:(CDRSpecBlock)block;
- (void)addInvariant:(CDRExampleBase *)inv;

@end
12 changes: 10 additions & 2 deletions Source/Headers/CDRSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,29 @@ extern "C" {
#endif
void beforeEach(CDRSpecBlock);
void afterEach(CDRSpecBlock);

CDRExample * invariant(NSString *, CDRSpecBlock);
extern CDRExample * (*it_should_always)(NSString *, CDRSpecBlock);

CDRExampleGroup * describe(NSString *, CDRSpecBlock);
extern CDRExampleGroup* (*context)(NSString *, CDRSpecBlock);

CDRExample * it(NSString *, CDRSpecBlock);

void subjectAction(CDRSpecBlock);

CDRExampleGroup * xdescribe(NSString *, CDRSpecBlock);
extern CDRExampleGroup* (*xcontext)(NSString *, CDRSpecBlock);
void subjectAction(CDRSpecBlock);
CDRExample * xit(NSString *, CDRSpecBlock);
CDRExample * xinvariant(NSString *, CDRSpecBlock);
extern CDRExample* (*xit_should_always)(NSString *, CDRSpecBlock);

CDRExampleGroup * fdescribe(NSString *, CDRSpecBlock);
extern CDRExampleGroup* (*fcontext)(NSString *, CDRSpecBlock);
CDRExample * fit(NSString *, CDRSpecBlock);

CDRExample * finvariant(NSString *, CDRSpecBlock);
extern CDRExample* (*fit_should_always)(NSString *, CDRSpecBlock);

void fail(NSString *);
#ifdef __cplusplus
}
Expand Down
Loading