Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
brentleyjones committed Jun 16, 2017
2 parents c57462c + 08608df commit 9bfbffc
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 120 deletions.
1 change: 1 addition & 0 deletions Cucumberish.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Pod::Spec.new do |s|
s.author = { "Ahmed Ali" => "eng.ahmed.ali.awad@gmail.com" }
s.social_media_url = "https://www.linkedin.com/in/engahmedali"
s.ios.deployment_target = "7.0"
s.tvos.deployment_target = "9.0"
s.osx.deployment_target = "10.9"
s.source = { :git => "https://github.com/Ahmed-Ali/Cucumberish.git", :tag => "v#{s.version}"}

Expand Down
3 changes: 2 additions & 1 deletion Cucumberish/Core/CCIBlockDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,11 @@ OBJC_EXTERN void Then(NSString * definitionString, CCIStepBody body);
@Note
Step definitions are checked in a "Last In First Out" order. If it happens that there are more than one definition matches a step, the last registered definition will be used.
@param definitionString the regular expression that will checked against each Given step line.
@param body the code block that will be executed if match is occured.
*/
__attribute__((deprecated("And is deprecated. Implement Given, When, Then or But instead")))
OBJC_EXTERN void And(NSString * definitionString, CCIStepBody body);

/**
Expand Down
69 changes: 56 additions & 13 deletions Cucumberish/Core/Managers/CCIFeaturesManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,63 +62,106 @@ - (instancetype) init
- (void)parseFeatureFiles:(NSArray *)featureFiles bundle:(NSBundle *)bundle withTags:(NSArray *)tags execludeFeaturesWithTags:(NSArray *)execludedFeatures
{
NSMutableArray * parsedFeatures = [NSMutableArray array];

GHParser * featureParser = [[GHParser alloc] init];
for (NSURL * filePath in featureFiles) {

id result = [featureParser parse:filePath.path];
if(result == nil){
//Nothing to do here...
//Need to think about how to report this error in non-blocker way
continue;
}
NSMutableDictionary * featureData = [[result dictionary] mutableCopy];

NSString * testBundlePath = [bundle bundlePath];
NSString * localPath = [[[filePath.absoluteString stringByRemovingPercentEncoding]
stringByReplacingOccurrencesOfString:testBundlePath withString:@""]
stringByReplacingOccurrencesOfString:@"file://" withString:@""];

featureData[@"location"][@"filePath"] = localPath;

CCIFeature * feature = [[CCIFeature alloc] initWithDictionary:featureData];
feature = [self cleanedUpFeature:feature includeTags:tags excludeTags:execludedFeatures];

if(feature != nil){
[parsedFeatures addObject:feature];
}

}

_features = parsedFeatures;
}

- (NSArray * __nullable)cleanedUpExcludedExamples:(NSArray *)examples excludeTags:(NSArray<NSString *> *)excludeTags
{
NSMutableArray * cleanedUpExamples = [NSMutableArray new];

// Won't be called unless there are excludeTags
for(CCIExample * example in examples) {
if([self tags:example.tags doesNotIntersectWithTags:excludeTags]){
[cleanedUpExamples addObject:example];
}
}
return cleanedUpExamples;
}

- (NSArray * __nullable)cleanedUpIncludedExamples:(NSArray *)examples includeTags:(NSArray<NSString *> *)includeTags
{
NSMutableArray * cleanedUpExamples = [NSMutableArray new];

// Will only be called if there are includeTags
for(CCIExample * example in examples) {
if([self tags:example.tags intersectWithTags:includeTags]) {
[cleanedUpExamples addObject:example];
}
}
return cleanedUpExamples;
}

- (NSArray * __nullable)cleanedUpScenarios:(NSArray *)scenarios includeTags:(NSArray<NSString *> *)includeTags excludeTags:(NSArray<NSString *> *)excludeTags
{
NSMutableArray * cleanedUpScenarios = [NSMutableArray new];

if(excludeTags.count > 0){
for(CCIScenarioDefinition * s in scenarios){
if([self tags:s.tags doesNotIntersectWithTags:excludeTags]){
[cleanedUpScenarios addObject:s];
// The scenario has not been excluded, but perhaps some (or all) of the examples have
if([s.keyword isEqualToString:(NSString *)kScenarioOutlineKeyword]) {
s.examples = [self cleanedUpExcludedExamples:s.examples excludeTags:excludeTags];
if(s.examples.count > 0) {
[cleanedUpScenarios addObject:s];
}
}else{
[cleanedUpScenarios addObject:s];
}
}
}
}else{
//If there is no excluding tags, nothing should be excluded
cleanedUpScenarios = [scenarios mutableCopy];
}

//At this point, cleanedUpScenarios holds the scenarios that have not been excluded
//Now we need to include only the scenarios that should be included
if(includeTags.count > 0){
NSMutableArray * matchingScnarios = [NSMutableArray new];
for(CCIScenarioDefinition * s in cleanedUpScenarios){
if([self tags:s.tags intersectWithTags:includeTags]){
[matchingScnarios addObject:s];
}else{
// The scenario has not been included, but perhaps some (or all) of the examples have
if([s.keyword isEqualToString:(NSString *)kScenarioOutlineKeyword]) {
s.examples = [self cleanedUpIncludedExamples:s.examples includeTags:includeTags];
if (s.examples.count > 0) {
[matchingScnarios addObject:s];
}
}
}
}
cleanedUpScenarios = matchingScnarios;
}

return cleanedUpScenarios;
}

Expand All @@ -130,7 +173,7 @@ - (CCIFeature * __nullable)cleanedUpFeature:(CCIFeature *)feature includeTags:(N
feature = nil;
}
}

feature.scenarioDefinitions = [self cleanedUpScenarios:feature.scenarioDefinitions includeTags:includeTags excludeTags:excludeTags];
if(feature.scenarioDefinitions.count == 0){
feature = nil;
Expand All @@ -147,7 +190,7 @@ - (BOOL)tags:(NSArray *)tags intersectWithTags:(NSArray *)tagsToCheckAgainst
break;
}
}

return intersect;
}

Expand Down
22 changes: 18 additions & 4 deletions Cucumberish/Core/Managers/CCIStepsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

@interface CCIStepsManager()
@property NSMutableDictionary * definitions;
@property (copy) NSString *currentContextKeyword;
@end

@implementation CCIStepsManager
Expand Down Expand Up @@ -86,7 +87,13 @@ - (CCIStepDefinition *)findMatchDefinitionForStep:(CCIStep *)step inTestCase:(id
}
return [self findDefinitionForStep:step amongDefinitions:allDefinitions inTestCase:testCase];
}
NSArray * definitionGroup = self.definitions[step.keyword];

NSArray *definitionGroup = self.definitions[step.keyword] ?: @[];
if ([step.keyword isEqualToString:@"And"]) {
NSArray *contextDefinitionGroup = self.definitions[self.currentContextKeyword];
definitionGroup = [definitionGroup arrayByAddingObjectsFromArray:contextDefinitionGroup];
}

return [self findDefinitionForStep:step amongDefinitions:definitionGroup inTestCase:testCase];

}
Expand All @@ -109,7 +116,7 @@ - (CCIStepDefinition *)findDefinitionForStep:(CCIStep *)step amongDefinitions:(N
//Only return nil if we reached the last definition without finding a match
break;
}
NSRange searchRange = NSMakeRange(0, [step.text lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
NSRange searchRange = NSMakeRange(0, [step.text length]);
NSTextCheckingResult * match = [[regex matchesInString:step.text options:NSMatchingReportCompletion range:searchRange] firstObject];

if (match.numberOfRanges > 1) {
Expand Down Expand Up @@ -153,6 +160,10 @@ - (CCIStepDefinition *)findDefinitionForStep:(CCIStep *)step amongDefinitions:(N

- (void)executeStep:(CCIStep *)step inTestCase:(id)testCase
{
if (![step.keyword isEqualToString:@"And"]) {
self.currentContextKeyword = step.keyword;
}

CCIStepDefinition * implementation = [self findMatchDefinitionForStep:step inTestCase:testCase];
NSString * errorMessage = nil;
if(step.keyword.length > 0){
Expand All @@ -165,7 +176,11 @@ - (void)executeStep:(CCIStep *)step inTestCase:(id)testCase
if(step.keyword.length > 0){
NSLog(@"Currently executing: \"%@ %@\"", step.keyword, step.text);
}


if ([step.keyword isEqualToString:@"And"]) {
implementation.type = @"And";
}

implementation.body(implementation.matchedValues, implementation.additionalContent);
//Clean up the step additional content to avoid keeping unwanted objects in memory
implementation.additionalContent = nil;
Expand Down Expand Up @@ -209,7 +224,6 @@ void MatchAll(NSString * definitionString, CCIStepBody body)
{
When(definitionString, body);
Then(definitionString, body);
And(definitionString, body);
But(definitionString, body);
}

Expand Down
19 changes: 14 additions & 5 deletions Cucumberish/Core/Models/CCIExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
| C1Ro1 | C2Ro1 | C3Ro1 |
| C1Ro2 | C2Ro2 | C3Ro2 |
| C1Ro3 | C2Ro3 | C3Ro3 |
@endcode
This will end up with the example data with the following structure
@code
{
Expand All @@ -71,18 +71,27 @@
*/
@property (nonatomic, strong) NSDictionary * exampleData;


/**
Array of tags found on top of this example table
*/
@property (nonatomic, strong) NSArray <NSString *> * tags;

@property (nonatomic, strong) NSArray<NSDictionary*>* rawTags;


/**
Creates an instance with properties filled from the passed dictionary
@param dictionary the dictionary that contains all the example data
@return example instance
*/
-(instancetype)initWithDictionary:(NSDictionary *)dictionary;

/**
Creates a dictionary from the class properties
@return the created dictionary
*/
-(NSDictionary *)toDictionary;
Expand Down
44 changes: 30 additions & 14 deletions Cucumberish/Core/Models/CCIExample.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ @implementation CCIExample
-(instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];

if(dictionary[@"location"] != nil && ![dictionary[@"location"] isKindOfClass:[NSNull class]]){
self.location = [[CCILocation alloc] initWithDictionary:dictionary[@"location"]];
}
Expand All @@ -57,11 +57,11 @@ -(instancetype)initWithDictionary:(NSDictionary *)dictionary
[headers addObject:cellValue];
exampleData[cellValue] = [NSMutableArray array];
}

}
if(dictionary[@"tableBody"] != nil && [dictionary[@"tableBody"] isKindOfClass:[NSArray class]]){
NSArray * rows = dictionary[@"tableBody"];

for(NSDictionary * row in rows){
NSArray * columns = row[@"cells"];
for(int i = 0; i < columns.count; i++){
Expand All @@ -71,12 +71,28 @@ -(instancetype)initWithDictionary:(NSDictionary *)dictionary
[tableColumn addObject:column[@"value"]];
}
}

}


if(dictionary[@"parsedTags"] != nil){
self.tags = dictionary[@"parsedTags"];
}else if(dictionary[@"tags"] != nil && [dictionary[@"tags"] isKindOfClass:[NSArray class]]){
NSArray * tagsDictionaries = dictionary[@"tags"];
self.rawTags = dictionary[@"tags"];
NSMutableArray * tagsItems = [NSMutableArray array];
for(NSDictionary * tagDictionary in tagsDictionaries){
NSString * tagName = tagDictionary[@"name"];
if([tagName hasPrefix:@"@"]){
tagName = [tagName stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
}
[tagsItems addObject:tagName];
}
self.tags = tagsItems;
}

self.exampleData = exampleData;
}

return self;
}

Expand All @@ -87,15 +103,15 @@ -(instancetype)initWithDictionary:(NSDictionary *)dictionary
-(NSDictionary *)toDictionary
{
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];

if(self.location != nil){
dictionary[@"location"] = [self.location toDictionary];
}

dictionary[@"exampleData"] = self.exampleData;

return dictionary;

}

/**
Expand All @@ -110,8 +126,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder
[aCoder encodeObject:self.location forKey:@"location"];
}
[aCoder encodeObject:self.exampleData forKey:@"exampleData"];


}

/**
Expand All @@ -123,6 +139,6 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder
self.location = [aDecoder decodeObjectForKey:@"location"];
self.exampleData = [aDecoder decodeObjectForKey:@"exampleData"];
return self;

}
@end
@end
6 changes: 6 additions & 0 deletions Cucumberish/Core/Models/CCIJSONDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@

+(NSString*)writeJSONToFile:(NSString*)filename
forFeatures:(NSArray<CCIFeature*>*)features;

+(NSString*)writeJSONToFile:(NSString*)filename
inDirectory:(NSString*) directory
forFeatures:(NSArray<CCIFeature*>*)features;


@end
Loading

0 comments on commit 9bfbffc

Please sign in to comment.