Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

mark examples as focused based on file name and line number

  • Loading branch information...
commit 3e8be308842e013c827eab795319e6468f14eac4 1 parent 944ce03
@cppforlife cppforlife authored
View
33 Cedar.xcodeproj/project.pbxproj
@@ -56,7 +56,16 @@
9637852F1491D84F0059C9F6 /* CDROTestHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 9637852D1491D84F0059C9F6 /* CDROTestHelper.h */; };
966E74ED145A6CA0002E8D49 /* ShouldSyntaxSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 966E74EC145A6CA0002E8D49 /* ShouldSyntaxSpec.mm */; };
966E74EE145A6CA0002E8D49 /* ShouldSyntaxSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 966E74EC145A6CA0002E8D49 /* ShouldSyntaxSpec.mm */; };
+ 9672F0A71615C1C10012ED58 /* CDRSymbolicatorSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */; };
+ 9672F0A91615C3F40012ED58 /* CDRSpecSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F0A81615C3F40012ED58 /* CDRSpecSpec.mm */; };
+ 9672F0AA1615C3F40012ED58 /* CDRSpecSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F0A81615C3F40012ED58 /* CDRSpecSpec.mm */; };
968BA92F143485F800EA40B3 /* CDROTestIPhoneRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 968BA92E143485F800EA40B3 /* CDROTestIPhoneRunner.h */; };
+ 968F9581161AC50800A78D36 /* CDRSymbolicatorSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */; };
+ 968F9582161AC58200A78D36 /* CDRSymbolicatorSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */; };
+ 969B6F84160C61E000C7C792 /* CDRSymbolicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 969B6F82160C61E000C7C792 /* CDRSymbolicator.m */; };
+ 969B6F86160C678400C7C792 /* CDRSymbolicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 969B6F82160C61E000C7C792 /* CDRSymbolicator.m */; };
+ 969B6F96160F1FEC00C7C792 /* CDRSymbolicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 969B6F95160F1FEC00C7C792 /* CDRSymbolicator.h */; };
+ 969B6F97160F1FEC00C7C792 /* CDRSymbolicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 969B6F95160F1FEC00C7C792 /* CDRSymbolicator.h */; };
96A07F0413F276640021974D /* Cedar.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AEEE1FB611DC271300029872 /* Cedar.framework */; };
96A07F0B13F276B10021974D /* FocusedSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A07F0A13F276B10021974D /* FocusedSpec.m */; };
96A07F0F13F27F2F0021974D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A07F0E13F27F2F0021974D /* main.m */; };
@@ -70,6 +79,7 @@
96B5FA12144A81A8000A6A5D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96B5F9F8144A81A7000A6A5D /* UIKit.framework */; };
96B5FA14144A81A8000A6A5D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96B5F9FB144A81A7000A6A5D /* CoreGraphics.framework */; };
96B5FA1C144A81A8000A6A5D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96B5FA1A144A81A8000A6A5D /* InfoPlist.strings */; };
+ 96C95B7E161339160018606B /* CDRSymbolicatorSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */; };
96D34482144A82DB00352C4A /* DummyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96D3447F144A82D100352C4A /* DummyView.xib */; };
96D34485144A845600352C4A /* OCUnitApplicationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96D34483144A845100352C4A /* OCUnitApplicationTests.mm */; };
96D3448A144A85A500352C4A /* libCedar-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AEEE222911DC2B0600029872 /* libCedar-StaticLib.a */; };
@@ -433,7 +443,10 @@
9637852A1491D6D30059C9F6 /* CDROTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDROTestHelper.m; sourceTree = "<group>"; };
9637852D1491D84F0059C9F6 /* CDROTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDROTestHelper.h; sourceTree = "<group>"; };
966E74EC145A6CA0002E8D49 /* ShouldSyntaxSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ShouldSyntaxSpec.mm; path = ../ShouldSyntaxSpec.mm; sourceTree = "<group>"; };
+ 9672F0A81615C3F40012ED58 /* CDRSpecSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CDRSpecSpec.mm; sourceTree = "<group>"; };
968BA92E143485F800EA40B3 /* CDROTestIPhoneRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDROTestIPhoneRunner.h; sourceTree = "<group>"; };
+ 969B6F82160C61E000C7C792 /* CDRSymbolicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRSymbolicator.m; sourceTree = "<group>"; };
+ 969B6F95160F1FEC00C7C792 /* CDRSymbolicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDRSymbolicator.h; sourceTree = "<group>"; };
96A07F0813F276640021974D /* FocusedSpecs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FocusedSpecs; sourceTree = BUILT_PRODUCTS_DIR; };
96A07F0A13F276B10021974D /* FocusedSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FocusedSpec.m; path = Focused/FocusedSpec.m; sourceTree = "<group>"; };
96A07F0E13F27F2F0021974D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Focused/main.m; sourceTree = "<group>"; };
@@ -452,6 +465,7 @@
96B5FA19144A81A8000A6A5D /* OCUnitAppTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "OCUnitAppTests-Info.plist"; sourceTree = "<group>"; };
96B5FA1B144A81A8000A6A5D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
96B5FA1D144A81A8000A6A5D /* OCUnitAppTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCUnitAppTests-Prefix.pch"; sourceTree = "<group>"; };
+ 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CDRSymbolicatorSpec.mm; sourceTree = "<group>"; };
96D34480144A82D100352C4A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DummyView.xib; sourceTree = "<group>"; };
96D34483144A845100352C4A /* OCUnitApplicationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OCUnitApplicationTests.mm; sourceTree = "<group>"; };
96E807BA1491BC7500388D9D /* OCUnitApplicationTestsWithSenTestingKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCUnitApplicationTestsWithSenTestingKit.m; sourceTree = "<group>"; };
@@ -929,6 +943,7 @@
96EA1CA6142C6425001A78E0 /* CDROTestReporter.m */,
96EA1CA7142C6425001A78E0 /* CDROTestRunner.m */,
9637852A1491D6D30059C9F6 /* CDROTestHelper.m */,
+ 969B6F82160C61E000C7C792 /* CDRSymbolicator.m */,
);
path = Source;
sourceTree = "<group>";
@@ -957,6 +972,7 @@
96EA1CAC142C6449001A78E0 /* CDROTestReporter.h */,
96EA1CAD142C6449001A78E0 /* CDROTestRunner.h */,
9637852D1491D84F0059C9F6 /* CDROTestHelper.h */,
+ 969B6F95160F1FEC00C7C792 /* CDRSymbolicator.h */,
);
path = Headers;
sourceTree = "<group>";
@@ -998,11 +1014,13 @@
AE8C879F1362068A006C9305 /* Matchers */,
66F00B5014C4D92500146D88 /* Doubles */,
96EA1CB9142C6560001A78E0 /* CDRSpecFailureSpec.mm */,
+ 9672F0A81615C3F40012ED58 /* CDRSpecSpec.mm */,
AEEE1FE811DC27B800029872 /* CDRExampleGroupSpec.mm */,
AEEE1FE911DC27B800029872 /* CDRExampleSpec.mm */,
AEEE1FE811DC27B800029872 /* CDRExampleGroupSpec.mm */,
492951E31482FF6200FA8916 /* CDRJUnitXMLReporterSpec.mm */,
AEEE1FF011DC27B800029872 /* GlobalBeforeEachSpec.mm */,
+ 96C95B7D161339160018606B /* CDRSymbolicatorSpec.mm */,
AEEE1FF111DC27B800029872 /* SpecSpec.mm */,
AEEE1FF211DC27B800029872 /* SpecSpec2.m */,
AEEE1FEF11DC27B800029872 /* main.m */,
@@ -1163,6 +1181,7 @@
AECF136715D142E3003AAB9C /* ReturnValue.h in Headers */,
AECF136A15D1439B003AAB9C /* AnyArgument.h in Headers */,
AE94D03F15F341B200A0C2B7 /* AnyInstanceArgument.h in Headers */,
+ 969B6F96160F1FEC00C7C792 /* CDRSymbolicator.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1177,6 +1196,7 @@
9637852F1491D84F0059C9F6 /* CDROTestHelper.h in Headers */,
492951DE1481AADA00FA8916 /* CDRJUnitXMLReporter.h in Headers */,
AE597B4215B0638B00EEF305 /* InvocationMatcher.h in Headers */,
+ 969B6F97160F1FEC00C7C792 /* CDRSymbolicator.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1471,6 +1491,7 @@
96158A9F144A91C4005895CE /* OCUnitAppLogicTests.mm in Sources */,
96158AA3144A9210005895CE /* DummyModel.m in Sources */,
96E807BD1491C6D200388D9D /* OCUnitAppLogicTestsWithSenTestingKit.m in Sources */,
+ 968F9581161AC50800A78D36 /* CDRSymbolicatorSpec.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1500,6 +1521,7 @@
files = (
96D34485144A845600352C4A /* OCUnitApplicationTests.mm in Sources */,
96E807BB1491BC7500388D9D /* OCUnitApplicationTestsWithSenTestingKit.m in Sources */,
+ 968F9582161AC58200A78D36 /* CDRSymbolicatorSpec.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1533,6 +1555,7 @@
AE94D04515F3449500A0C2B7 /* AnyInstanceArgument.mm in Sources */,
AEC7873915F440980058A27B /* InvocationMatcher.mm in Sources */,
AEC7874D15F444A50058A27B /* HaveReceived.mm in Sources */,
+ 969B6F84160C61E000C7C792 /* CDRSymbolicator.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1540,12 +1563,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- AEEE21BE11DC290400029872 /* CDRExampleGroupSpec.mm in Sources */,
+ AEEE21C411DC290400029872 /* SpecSpec2.m in Sources */,
AEEE21BF11DC290400029872 /* CDRExampleSpec.mm in Sources */,
+ AEEE21BE11DC290400029872 /* CDRExampleGroupSpec.mm in Sources */,
AEEE21C111DC290400029872 /* main.m in Sources */,
AEEE21C211DC290400029872 /* GlobalBeforeEachSpec.mm in Sources */,
AEEE21C311DC290400029872 /* SpecSpec.mm in Sources */,
- AEEE21C411DC290400029872 /* SpecSpec2.m in Sources */,
AE8C87AE136245BB006C9305 /* ExpectFailureWithMessage.m in Sources */,
96EA1CBA142C6560001A78E0 /* CDRSpecFailureSpec.mm in Sources */,
AEF7301B13ECC4AE00786282 /* BeCloseToSpec.mm in Sources */,
@@ -1571,6 +1594,8 @@
AE9AA69715ADB99800617E1A /* CedarDoubleSharedExamples.mm in Sources */,
AE74903215B45EBA008EA127 /* CDRProtocolFakeSpec.mm in Sources */,
AE36AC6215B4BBFB00EB6C51 /* NoOpKeyValueObserver.m in Sources */,
+ 96C95B7E161339160018606B /* CDRSymbolicatorSpec.mm in Sources */,
+ 9672F0A91615C3F40012ED58 /* CDRSpecSpec.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1610,6 +1635,7 @@
AE94D04615F3449500A0C2B7 /* AnyInstanceArgument.mm in Sources */,
AEC7873A15F440980058A27B /* InvocationMatcher.mm in Sources */,
AEC7874E15F444A50058A27B /* HaveReceived.mm in Sources */,
+ 969B6F86160C678400C7C792 /* CDRSymbolicator.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1646,6 +1672,8 @@
AE9AA68E15ACD8D400617E1A /* SimpleIncrementer.m in Sources */,
AE9AA69815ADB99800617E1A /* CedarDoubleSharedExamples.mm in Sources */,
AE36AC6315B4BBFC00EB6C51 /* NoOpKeyValueObserver.m in Sources */,
+ 9672F0A71615C1C10012ED58 /* CDRSymbolicatorSpec.mm in Sources */,
+ 9672F0AA1615C3F40012ED58 /* CDRSpecSpec.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1734,6 +1762,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
+ GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "OCUnitAppLogicTests/OCUnitAppLogicTests-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
View
2  Source/CDRExampleBase.m
@@ -3,7 +3,7 @@
@implementation CDRExampleBase
-@synthesize text = text_, parent = parent_, focused = focused_;
+@synthesize text = text_, parent = parent_, focused = focused_, stackAddress = stackAddress_;
- (id)initWithText:(NSString *)text {
if (self = [super init]) {
View
109 Source/CDRFunctions.m
@@ -1,12 +1,14 @@
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
-#import <objc/message.h>
#import "CDRSpec.h"
+#import "CDRExampleGroup.h"
#import "CDRExampleReporter.h"
#import "CDRDefaultReporter.h"
#import "SpecHelper.h"
#import "CDRFunctions.h"
+#pragma mark - Helpers
+
BOOL CDRClassIsOfType(Class class, const char * const className) {
Protocol * protocol = NSProtocolFromString([NSString stringWithCString:className encoding:NSUTF8StringEncoding]);
if (strcmp(className, class_getName(class))) {
@@ -37,19 +39,13 @@ BOOL CDRClassIsOfType(Class class, const char * const className) {
return selectedClasses;
}
-NSArray *CDRCreateRootGroupsFromSpecClasses(NSArray *specClasses) {
- NSMutableArray *rootGroups = [[NSMutableArray alloc] initWithCapacity:[specClasses count]];
- for (Class class in specClasses) {
- CDRSpec *spec = [[class alloc] init];
- [spec defineBehaviors];
- [rootGroups addObject:spec.rootGroup];
- [spec release];
- }
- return rootGroups;
-}
+#pragma mark - Globals
void CDRDefineSharedExampleGroups() {
- NSArray *sharedExampleGroupPoolClasses = CDRSelectClasses(^(Class class) { return CDRClassIsOfType(class, "CDRSharedExampleGroupPool"); });
+ NSArray *sharedExampleGroupPoolClasses = CDRSelectClasses(^(Class class) {
+ return CDRClassIsOfType(class, "CDRSharedExampleGroupPool");
+ });
+
for (Class class in sharedExampleGroupPoolClasses) {
CDRSharedExampleGroupPool *sharedExampleGroupPool = [[class alloc] init];
[sharedExampleGroupPool declareSharedExampleGroups];
@@ -65,10 +61,17 @@ BOOL CDRClassHasClassMethod(Class class, SEL selector) {
}
void CDRDefineGlobalBeforeAndAfterEachBlocks() {
- [SpecHelper specHelper].globalBeforeEachClasses = CDRSelectClasses(^BOOL(Class class) { return CDRClassHasClassMethod(class, @selector(beforeEach)); });
- [SpecHelper specHelper].globalAfterEachClasses = CDRSelectClasses(^BOOL(Class class) { return CDRClassHasClassMethod(class, @selector(afterEach)); });
+ [SpecHelper specHelper].globalBeforeEachClasses = CDRSelectClasses(^BOOL(Class class) {
+ return CDRClassHasClassMethod(class, @selector(beforeEach));
+ });
+
+ [SpecHelper specHelper].globalAfterEachClasses = CDRSelectClasses(^BOOL(Class class) {
+ return CDRClassHasClassMethod(class, @selector(afterEach));
+ });
}
+#pragma mark - Reporters
+
NSArray *CDRReporterClassesFromEnv(const char *defaultReporterClassName) {
const char *reporterClassNamesCsv = getenv("CEDAR_REPORTER_CLASS");
if (!reporterClassNamesCsv) {
@@ -87,56 +90,87 @@ void CDRDefineGlobalBeforeAndAfterEachBlocks() {
}
[reporterClasses addObject:reporterClass];
}
-
return reporterClasses;
}
NSArray *CDRReportersFromEnv(const char *defaultReporterClassName) {
NSArray *reporterClasses = CDRReporterClassesFromEnv(defaultReporterClassName);
- NSMutableArray *reporters = [NSMutableArray arrayWithCapacity:[reporterClasses count]];
+ NSMutableArray *reporters = [NSMutableArray arrayWithCapacity:reporterClasses.count];
for (Class reporterClass in reporterClasses) {
[reporters addObject:[[[reporterClass alloc] init] autorelease]];
}
-
return reporters;
}
+#pragma mark - Spec running
+
NSArray *CDRSpecClassesToRun() {
char *envSpecClassNames = getenv("CEDAR_SPEC_CLASSES");
if (envSpecClassNames) {
- NSArray *specClassNames = [[NSString stringWithCString:envSpecClassNames encoding:NSUTF8StringEncoding] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
- NSMutableArray *specClassesToRun = [NSMutableArray arrayWithCapacity:[specClassNames count]];
+ NSArray *specClassNames =
+ [[NSString stringWithUTF8String:envSpecClassNames]
+ componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+ NSMutableArray *specClassesToRun = [NSMutableArray arrayWithCapacity:specClassNames.count];
+
for (NSString *className in specClassNames) {
Class specClass = NSClassFromString(className);
- if (specClass) {
- [specClassesToRun addObject:specClass];
- }
+ if (specClass) [specClassesToRun addObject:specClass];
}
return [[specClassesToRun copy] autorelease];
}
- return nil;
+
+ return CDRSelectClasses(^(Class class) {
+ return CDRClassIsOfType(class, "CDRSpec");
+ });
}
-int runSpecsWithCustomExampleReporters(NSArray *reporters) {
- @autoreleasepool {
- NSArray *specClasses = CDRSpecClassesToRun();
- if (!specClasses) {
- specClasses = CDRSelectClasses(^(Class class) { return CDRClassIsOfType(class, "CDRSpec"); });
+NSArray *CDRSpecsFromSpecClasses(NSArray *specClasses) {
+ NSMutableArray *specs = [NSMutableArray arrayWithCapacity:specClasses.count];
+ for (Class class in specClasses) {
+ CDRSpec *spec = [[[class alloc] init] autorelease];
+ [spec defineBehaviors];
+ [specs addObject:spec];
+ }
+ return specs;
+}
+
+void CDRMarkFocusedExamplesInSpecs(NSArray *specs) {
+ char *envSpecFile = getenv("CEDAR_SPEC_FILE");
+ if (envSpecFile) {
+ NSArray *components = [[NSString stringWithUTF8String:envSpecFile] componentsSeparatedByString:@":"];
+
+ for (CDRSpec *spec in specs) {
+ if ([spec.fileName isEqualToString:[components objectAtIndex:0]]) {
+ [spec markAsFocusedClosestToLineNumber:[[components objectAtIndex:1] intValue]];
+ }
}
+ }
+
+ for (CDRSpec *spec in specs) {
+ SpecHelper.specHelper.shouldOnlyRunFocused |= spec.rootGroup.hasFocusedExamples;
+ }
+}
+
+NSArray *CDRRootGroupsFromSpecs(NSArray *specs) {
+ NSMutableArray *groups = [NSMutableArray arrayWithCapacity:specs.count];
+ for (CDRSpec *spec in specs) {
+ [groups addObject:spec.rootGroup];
+ }
+ return groups;
+}
+int runSpecsWithCustomExampleReporters(NSArray *reporters) {
+ @autoreleasepool {
CDRDefineSharedExampleGroups();
CDRDefineGlobalBeforeAndAfterEachBlocks();
- NSArray *groups = CDRCreateRootGroupsFromSpecClasses(specClasses);
-
- for (CDRExampleGroup *group in groups) {
- [SpecHelper specHelper].shouldOnlyRunFocused |= [group hasFocusedExamples];
- }
- for (id<CDRExampleReporter> reporter in reporters) {
- [reporter runWillStartWithGroups:groups];
- }
+ NSArray *specClasses = CDRSpecClassesToRun();
+ NSArray *specs = CDRSpecsFromSpecClasses(specClasses);
+ CDRMarkFocusedExamplesInSpecs(specs);
+ NSArray *groups = CDRRootGroupsFromSpecs(specs);
+ [reporters makeObjectsPerformSelector:@selector(runWillStartWithGroups:) withObject:groups];
[groups makeObjectsPerformSelector:@selector(run)];
int result = 0;
@@ -144,8 +178,6 @@ int runSpecsWithCustomExampleReporters(NSArray *reporters) {
[reporter runDidComplete];
result |= [reporter result];
}
-
- [groups release];
return result;
}
}
@@ -156,7 +188,6 @@ int runSpecs() {
if (![reporters count]) {
@throw @"No reporters? WTF?";
}
-
return runSpecsWithCustomExampleReporters(reporters);
}
}
View
101 Source/CDRSpec.m
@@ -3,6 +3,7 @@
#import "CDRExampleGroup.h"
#import "CDRSpecFailure.h"
#import "SpecHelper.h"
+#import "CDRSymbolicator.h"
CDRSpec *currentSpec;
@@ -14,6 +15,9 @@ void afterEach(CDRSpecBlock block) {
[currentSpec.currentGroup addAfter:block];
}
+#define with_stack_address(b) \
+ (b.stackAddress = CDRCallerStackAddress()) ? b : b
+
CDRExampleGroup * describe(NSString *text, CDRSpecBlock block) {
CDRExampleGroup *parentGroup = currentSpec.currentGroup;
@@ -25,45 +29,45 @@ void afterEach(CDRSpecBlock block) {
block();
currentSpec.currentGroup = parentGroup;
}
- return group;
+ return with_stack_address(group);
}
-CDRExampleGroup * context(NSString *text, CDRSpecBlock block) {
- return describe(text, block);
-}
+CDRExampleGroup* (*context)(NSString *, CDRSpecBlock) = &describe;
CDRExample * it(NSString *text, CDRSpecBlock block) {
CDRExample *example = [CDRExample exampleWithText:text andBlock:block];
[currentSpec.currentGroup add:example];
- return example;
+ return with_stack_address(example);
}
+#pragma mark - Pending
+
CDRExampleGroup * xdescribe(NSString *text, CDRSpecBlock block) {
- return describe(text, ^{});
+ CDRExampleGroup *group = describe(text, ^{});
+ return with_stack_address(group);
}
-CDRExampleGroup * xcontext(NSString *text, CDRSpecBlock block) {
- return xdescribe(text, block);
-}
+CDRExampleGroup* (*xcontext)(NSString *, CDRSpecBlock) = &xdescribe;
CDRExample * xit(NSString *text, CDRSpecBlock block) {
- return it(text, PENDING);
+ CDRExample *example = it(text, PENDING);
+ return with_stack_address(example);
}
+#pragma mark - Focused
+
CDRExampleGroup * fdescribe(NSString *text, CDRSpecBlock block) {
CDRExampleGroup *group = describe(text, block);
group.focused = YES;
- return group;
+ return with_stack_address(group);
}
-CDRExampleGroup * fcontext(NSString *text, CDRSpecBlock block) {
- return fdescribe(text, block);
-}
+CDRExampleGroup* (*fcontext)(NSString *, CDRSpecBlock) = &fdescribe;
CDRExample * fit(NSString *text, CDRSpecBlock block) {
CDRExample *example = it(text, block);
example.focused = YES;
- return example;
+ return with_stack_address(example);
}
void fail(NSString *reason) {
@@ -72,7 +76,11 @@ void fail(NSString *reason) {
@implementation CDRSpec
-@synthesize currentGroup = currentGroup_, rootGroup = rootGroup_;
+@synthesize
+ currentGroup = currentGroup_,
+ rootGroup = rootGroup_,
+ fileName = fileName_,
+ symbolicator = symbolicator_;
#pragma mark Memory
- (id)init {
@@ -87,7 +95,8 @@ - (id)init {
- (void)dealloc {
self.rootGroup = nil;
self.currentGroup = nil;
-
+ self.fileName = nil;
+ self.symbolicator = nil;
[super dealloc];
}
@@ -98,7 +107,63 @@ - (void)defineBehaviors {
}
- (void)failWithException:(NSException *)exception {
- [[CDRSpecFailure specFailureWithReason:[exception reason]] raise];
+ [[CDRSpecFailure specFailureWithReason:exception.reason] raise];
+}
+
+- (void)markAsFocusedClosestToLineNumber:(NSUInteger)lineNumber {
+ NSArray *children = self.allChildren;
+ if (children.count == 0) return;
+
+ NSMutableArray *addresses = [NSMutableArray array];
+ for (CDRExampleBase *child in children) {
+ [addresses addObject:[NSNumber numberWithUnsignedInteger:child.stackAddress]];
+ }
+
+ // Use symbolication to find out locations of examples.
+ // We cannot turn describe/it/context into macros because:
+ // - making them non-function macros pollutes namespace
+ // - making them function macros causes xcode to highlight
+ // wrong lines of code if there are errors present in the code
+ // - also __LINE__ is unrolled from the outermost block
+ // which causes incorrect values
+ [self.symbolicator symbolicateAddresses:addresses];
+
+ int bestAddressIndex = [children indexOfObject:self.rootGroup];
+
+ // Matches closest example/group located on or below specifed line number
+ // (only takes into account start of an example/group)
+ for (int i = 0, shortestDistance = -1; i < addresses.count; i++) {
+ NSUInteger address = [[addresses objectAtIndex:i] unsignedIntegerValue];
+ int distance = lineNumber - [self.symbolicator lineNumberForStackAddress:address];
+
+ if (distance >= 0 && (distance < shortestDistance || shortestDistance == -1) ) {
+ bestAddressIndex = i;
+ shortestDistance = distance;
+ }
+ }
+ [[children objectAtIndex:bestAddressIndex] setFocused:YES];
+}
+
+- (NSArray *)allChildren {
+ NSMutableArray *unseenChildren = [NSMutableArray arrayWithObject:self.rootGroup];
+ NSMutableArray *seenChildren = [NSMutableArray array];
+
+ while (unseenChildren.count > 0) {
+ CDRExampleBase *child = [unseenChildren lastObject];
+ [unseenChildren removeLastObject];
+
+ if (child.hasChildren) {
+ [unseenChildren addObjectsFromArray:[(CDRExampleGroup *)child examples]];
+ }
+ [seenChildren addObject:child];
+ }
+ return seenChildren;
}
+- (CDRSymbolicator *)symbolicator {
+ if (!symbolicator_) {
+ symbolicator_ = [[CDRSymbolicator alloc] init];
+ }
+ return symbolicator_;
+}
@end
View
227 Source/CDRSymbolicator.m
@@ -0,0 +1,227 @@
+#import "CDRSymbolicator.h"
+#import <objc/runtime.h>
+#import <mach-o/dyld.h>
+#import <libunwind.h>
+#import <regex.h>
+
+NSUInteger CDRCallerStackAddress() {
+#if __arm__ // libunwind functions are not available
+ return 0;
+#else
+ unw_context_t uc;
+ if (unw_getcontext(&uc) != 0) return 0;
+
+ unw_cursor_t cursor;
+ if (unw_init_local(&cursor, &uc) != 0) return 0;
+
+ NSUInteger stackAddress = 0;
+ int depth = 2; // caller of caller of CDRCallerStackAddress
+
+ while (unw_step(&cursor) > 0 && depth-- > 0) {
+ unw_word_t ip;
+ if (unw_get_reg(&cursor, UNW_REG_IP, &ip) != 0) return 0;
+ stackAddress = (NSUInteger)(ip - 4);
+ }
+ return stackAddress;
+#endif
+}
+
+@interface CDRSymbolicator ()
+@property (nonatomic, retain) NSMutableArray *addresses, *fileNames, *lineNumbers;
+@end
+
+@implementation CDRSymbolicator
+@synthesize
+ addresses = addresses_,
+ fileNames = fileNames_,
+ lineNumbers = lineNumbers_;
+
+- (id)init {
+ if (self = [super init]) {
+ self.addresses = [NSMutableArray array];
+ self.fileNames = [NSMutableArray array];
+ self.lineNumbers = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ self.addresses = nil;
+ self.fileNames = nil;
+ self.lineNumbers = nil;
+ [super dealloc];
+}
+
+- (NSString *)fileNameForStackAddress:(NSUInteger)address {
+ NSUInteger index = [self.addresses indexOfObject:[NSNumber numberWithUnsignedInteger:address]];
+ return (index == NSNotFound) ? nil : [self.fileNames objectAtIndex:index];
+}
+
+- (NSUInteger)lineNumberForStackAddress:(NSUInteger)address {
+ NSUInteger index = [self.addresses indexOfObject:[NSNumber numberWithUnsignedInteger:address]];
+ return (index == NSNotFound) ? 0 : [[self.lineNumbers objectAtIndex:index] unsignedIntegerValue];
+}
+
+- (void)symbolicateAddresses:(NSArray *)addresses {
+ NSArray *validAddresses = [self.class validAddresses:addresses];
+
+ CDRAtosTask *atosTask = [CDRAtosTask taskForCurrentTestExecutable];
+ atosTask.addresses = validAddresses;
+ [atosTask launch];
+
+ for (int i=0; i<validAddresses.count; i++) {
+ NSString *fileName = nil;
+ NSNumber *lineNumber = [NSNumber numberWithInt:0];
+ [atosTask valuesOnLineNumber:i fileName:&fileName lineNumber:&lineNumber];
+
+ if (fileName) {
+ [self.addresses addObject:[validAddresses objectAtIndex:i]];
+ [self.fileNames addObject:fileName];
+ [self.lineNumbers addObject:lineNumber];
+ }
+ }
+}
+
++ (NSArray *)validAddresses:(NSArray *)addresses {
+ NSMutableArray *validAddresses = [NSMutableArray array];
+ for (NSNumber *address in addresses) {
+ if (address.unsignedIntegerValue > 0)
+ [validAddresses addObject:address];
+ }
+ return validAddresses;
+}
+@end
+
+
+@interface CDRAtosTask ()
+@property (retain, nonatomic) NSArray *outputLines;
+@end
+
+@interface CDRAtosTask (NSTaskStubs)
+- (void)setLaunchPath:(NSString *)path;
+- (void)setArguments:(NSArray *)arguments;
+- (void)setEnvironment:(NSDictionary *)dict;
+
+- (void)setStandardOutput:(NSPipe *)pipe;
+- (void)launch;
+- (void)waitUntilExit;
+@end
+
+@implementation CDRAtosTask
+
+@synthesize
+ executablePath = executablePath_,
+ slide = slide_,
+ addresses = addresses_,
+ outputLines = outputLines_;
+
+- (id)initWithExecutablePath:(NSString *)executablePath slide:(long)slide addresses:(NSArray *)addresses {
+ if (self = [super init]) {
+ self.executablePath = executablePath;
+ self.slide = slide;
+ self.addresses = addresses;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ self.executablePath = nil;
+ self.addresses = nil;
+ self.outputLines = nil;
+ [super dealloc];
+}
+
+- (void)launch {
+ NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-o", self.executablePath, nil];
+
+ // Position-independent executables addresses need to be adjusted hence the slide argument
+ // https://developer.apple.com/library/mac/#technotes/tn2004/tn2123.html
+ [arguments addObject:@"-s"];
+ [arguments addObject:[NSString stringWithFormat:@"%lx", self.slide]];
+
+ for (NSNumber *address in self.addresses) {
+ [arguments addObject:[NSString stringWithFormat:@"%lx", (long)address.unsignedIntegerValue]];
+ }
+
+ NSString *output = [self.class shellOutWithCommand:@"/usr/bin/atos" arguments:arguments];
+ self.outputLines = [output componentsSeparatedByString:@"\n"];
+}
+
++ (regex_t)lineRegex {
+ static regex_t *rx = NULL;
+ if (!rx) {
+ rx = malloc(sizeof(regex_t));
+ regcomp(rx, "^.+\\((.+):([[:digit:]]+)\\)$", REG_EXTENDED); // __block_global_1 (in Specs) (SpecSpec2.m:12)
+ }
+ return *rx; // leaks rx; regfree(&rx);
+}
+
+- (void)valuesOnLineNumber:(NSUInteger)line fileName:(NSString **)fileName lineNumber:(NSNumber **)lineNumber {
+ if (line >= self.outputLines.count) return;
+
+ regex_t rx = [self.class lineRegex];
+ regmatch_t *matches = (regmatch_t *)malloc((rx.re_nsub+1) * sizeof(regmatch_t));
+
+ const char *buf = [[self.outputLines objectAtIndex:line] UTF8String];
+
+ if (regexec(&rx, buf, rx.re_nsub+1, matches, 0) == 0) {
+ *fileName = [[[NSString alloc]
+ initWithBytes:(buf + matches[1].rm_so)
+ length:(NSInteger)(matches[1].rm_eo - matches[1].rm_so)
+ encoding:NSUTF8StringEncoding] autorelease];
+
+ NSString *lineNumberStr = [[[NSString alloc]
+ initWithBytes:(buf + matches[2].rm_so)
+ length:(NSInteger)(matches[2].rm_eo - matches[2].rm_so)
+ encoding:NSUTF8StringEncoding] autorelease];
+
+ *lineNumber = [NSNumber numberWithInteger:lineNumberStr.integerValue];
+ } else {
+ printf("atos was not able to symbolicate '%s'.\n", buf);
+ printf("Try setting compiler Optimization Level to None (-O0).\n");
+ }
+ free(matches);
+}
+
++ (NSString *)shellOutWithCommand:(NSString *)command arguments:(NSArray *)arguments {
+ id task = [[NSClassFromString(@"NSTask") alloc] init]; // trick iOS SDK in simulator
+ [task setEnvironment:[NSDictionary dictionary]];
+ [task setLaunchPath:command];
+ [task setArguments:arguments];
+
+ NSPipe *pipe = [NSPipe pipe];
+ [task setStandardOutput:pipe];
+ [task launch];
+ [task waitUntilExit];
+
+ NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
+ NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
+ [task release];
+
+ return string;
+}
+@end
+
+@implementation CDRAtosTask (CurrentTestExecutable)
+
++ (CDRAtosTask *)taskForCurrentTestExecutable {
+ NSString *executablePath = [[NSBundle mainBundle] executablePath];
+ long slide = _dyld_get_image_vmaddr_slide(0);
+
+ // If running with SenTestingKit use test bundle executable
+ if (objc_getClass("SenTestProbe"))
+ [self getOtestBundleExecutablePath:&executablePath slide:&slide];
+
+ return [[[self alloc] initWithExecutablePath:executablePath slide:slide addresses:nil] autorelease];
+}
+
++ (void)getOtestBundleExecutablePath:(NSString **)executablePath slide:(long *)slide {
+ for (int i=0; i<_dyld_image_count(); i++) {
+ if (strstr(_dyld_get_image_name(i), ".octest/") != NULL) {
+ *executablePath = [NSString stringWithUTF8String:_dyld_get_image_name(i)];
+ *slide = _dyld_get_image_vmaddr_slide(i);
+ return;
+ }
+ }
+}
+@end
View
1  Source/Headers/CDRExampleBase.h
@@ -24,6 +24,7 @@ typedef enum CDRExampleState CDRExampleState;
@property (nonatomic, readonly) NSString *text;
@property (nonatomic, assign) id<CDRExampleParent> parent;
@property (nonatomic, assign, getter=isFocused) BOOL focused;
+@property (nonatomic) NSUInteger stackAddress;
- (id)initWithText:(NSString *)text;
View
1  Source/Headers/CDRExampleGroup.h
@@ -2,6 +2,7 @@
@interface CDRExampleGroup : CDRExampleBase <CDRExampleParent> {
NSMutableArray *beforeBlocks_, *examples_, *afterBlocks_;
+ NSUInteger stackAddress_;
BOOL isRoot_;
}
View
1  Source/Headers/CDRExampleParent.h
@@ -12,4 +12,5 @@
- (NSString *)fullText;
- (NSMutableArray *)fullTextInPieces;
+- (NSUInteger)stackAddress;
@end
View
21 Source/Headers/CDRSpec.h
@@ -2,7 +2,7 @@
#import "CDRExampleBase.h"
@protocol CDRExampleReporter;
-@class CDRExampleGroup, CDRExample, SpecHelper;
+@class CDRExampleGroup, CDRExample, SpecHelper, CDRSymbolicator;
@protocol CDRSpec
@end
@@ -16,15 +16,15 @@ void beforeEach(CDRSpecBlock);
void afterEach(CDRSpecBlock);
CDRExampleGroup * describe(NSString *, CDRSpecBlock);
-CDRExampleGroup * context(NSString *, CDRSpecBlock);
+extern CDRExampleGroup* (*context)(NSString *, CDRSpecBlock);
CDRExample * it(NSString *, CDRSpecBlock);
-CDRExampleGroup * xcontext(NSString *, CDRSpecBlock);
CDRExampleGroup * xdescribe(NSString *, CDRSpecBlock);
+extern CDRExampleGroup* (*xcontext)(NSString *, CDRSpecBlock);
CDRExample * xit(NSString *, CDRSpecBlock);
CDRExampleGroup * fdescribe(NSString *, CDRSpecBlock);
-CDRExampleGroup * fcontext(NSString *, CDRSpecBlock);
+extern CDRExampleGroup* (*fcontext)(NSString *, CDRSpecBlock);
CDRExample * fit(NSString *, CDRSpecBlock);
void fail(NSString *);
@@ -40,12 +40,18 @@ void fail(NSString *);
#endif // __cplusplus
@interface CDRSpec : NSObject <CDRSpec> {
- CDRExampleGroup *rootGroup_;
- CDRExampleGroup *currentGroup_;
+ CDRExampleGroup *rootGroup_;
+ CDRExampleGroup *currentGroup_;
+ NSString *fileName_;
+ CDRSymbolicator *symbolicator_;
}
@property (nonatomic, retain) CDRExampleGroup *currentGroup, *rootGroup;
+@property (nonatomic, retain) NSString *fileName;
+@property (nonatomic, retain) CDRSymbolicator *symbolicator;
+
- (void)defineBehaviors;
+- (void)markAsFocusedClosestToLineNumber:(NSUInteger)lineNumber;
@end
@interface CDRSpec (SpecDeclaration)
@@ -56,7 +62,8 @@ void fail(NSString *);
@interface name : CDRSpec \
@end \
@implementation name \
-- (void)declareBehaviors {
+- (void)declareBehaviors { \
+ self.fileName = [NSString stringWithUTF8String:__FILE__];
#define SPEC_END \
} \
View
32 Source/Headers/CDRSymbolicator.h
@@ -0,0 +1,32 @@
+#import <Foundation/Foundation.h>
+
+NSUInteger CDRCallerStackAddress();
+
+@interface CDRSymbolicator : NSObject
+- (id)init;
+- (void)symbolicateAddresses:(NSArray *)addresses;
+
+- (NSString *)fileNameForStackAddress:(NSUInteger)address;
+- (NSUInteger)lineNumberForStackAddress:(NSUInteger)address;
+@end
+
+
+@interface CDRAtosTask : NSObject {
+ NSString *executablePath_;
+ long slide_;
+ NSArray *addresses_;
+ NSArray *outputLines_;
+}
+
+@property (retain, nonatomic) NSString *executablePath;
+@property (assign, nonatomic) long slide;
+@property (retain, nonatomic) NSArray *addresses;
+
+- (id)initWithExecutablePath:(NSString *)executablePath slide:(long)slide addresses:(NSArray *)addresses;
+- (void)launch;
+- (void)valuesOnLineNumber:(NSUInteger)line fileName:(NSString **)fileName lineNumber:(NSNumber **)lineNumber;
+@end
+
+@interface CDRAtosTask (CurrentTestExecutable)
++ (CDRAtosTask *)taskForCurrentTestExecutable;
+@end
View
97 Spec/CDRSpecSpec.mm
@@ -0,0 +1,97 @@
+#if TARGET_OS_IPHONE
+// Normally you would include this file out of the framework. However, we're
+// testing the framework here, so including the file from the framework will
+// conflict with the compiler attempting to include the file from the project.
+#import "SpecHelper.h"
+#else
+#import <Cedar/SpecHelper.h>
+#endif
+
+#import "CDRSpec.h"
+#import "CDRExampleGroup.h"
+
+using namespace Cedar::Matchers;
+using namespace Cedar::Doubles;
+
+SPEC_BEGIN(CDRSpecSpec)
+
+describe(@"CDRSpec", ^{
+ __block CDRSpec *spec;
+
+ beforeEach(^{
+ spec = [[[CDRSpec alloc] init] autorelease];
+
+ spy_on(spec.symbolicator);
+ spec.symbolicator stub_method("symbolicateAddresses:");
+ spec.symbolicator stub_method("lineNumberForStackAddress:").and_do(^(NSInvocation *i){
+ NSUInteger lineNumber;
+ [i getArgument:&lineNumber atIndex:2];
+ [i setReturnValue:&lineNumber];
+ });
+ });
+
+ CDRExampleGroup *(^exampleGroup)(int) = ^(int lineNumber){
+ CDRExampleGroup *group = [[[CDRExampleGroup alloc] initWithText:@"Group"] autorelease];
+ group.stackAddress = lineNumber;
+ return group;
+ };
+
+ describe(@"-markAsFocusedClosestToLineNumber:", ^{
+ context(@"with a single group", ^{
+ it(@"marks group as focused if line number is above the group", ^{
+ spec.rootGroup = exampleGroup(1);
+ [spec markAsFocusedClosestToLineNumber:0];
+ spec.rootGroup.isFocused should be_truthy;
+ });
+
+ it(@"marks group as focused if line number is exactly on the first line of the group", ^{
+ spec.rootGroup = exampleGroup(1);
+ [spec markAsFocusedClosestToLineNumber:1];
+ spec.rootGroup.isFocused should be_truthy;
+ });
+
+ it(@"marks group as focused if line number is below the first line of the group", ^{
+ spec.rootGroup = exampleGroup(1);
+ [spec markAsFocusedClosestToLineNumber:2];
+ spec.rootGroup.isFocused should be_truthy;
+ });
+ });
+
+ context(@"with a group that contains another group", ^{
+ it(@"marks outer group as focused if line number is below the first line of outer group and above the first line of inner group", ^{
+ spec.rootGroup = exampleGroup(1);
+
+ CDRExampleGroup *innerGroup = exampleGroup(3);
+ [spec.rootGroup add:innerGroup];
+
+ [spec markAsFocusedClosestToLineNumber:2];
+ spec.rootGroup.isFocused should be_truthy;
+ innerGroup.isFocused should_not be_truthy;
+ });
+
+ it(@"marks inner group as focused if line number is below the first line of outer group and exactly on the first line of inner group", ^{
+ spec.rootGroup = exampleGroup(1);
+
+ CDRExampleGroup *innerGroup = exampleGroup(3);
+ [spec.rootGroup add:innerGroup];
+
+ [spec markAsFocusedClosestToLineNumber:3];
+ spec.rootGroup.isFocused should_not be_truthy;
+ innerGroup.isFocused should be_truthy;
+ });
+
+ it(@"marks inner group as focused if line number is below both first lines of outer and inner groups", ^{
+ spec.rootGroup = exampleGroup(1);
+
+ CDRExampleGroup *innerGroup = exampleGroup(3);
+ [spec.rootGroup add:innerGroup];
+
+ [spec markAsFocusedClosestToLineNumber:5];
+ spec.rootGroup.isFocused should_not be_truthy;
+ innerGroup.isFocused should be_truthy;
+ });
+ });
+ });
+});
+
+SPEC_END
View
66 Spec/CDRSymbolicatorSpec.mm
@@ -0,0 +1,66 @@
+#import "SpecHelper.h"
+#import "CDRExample.h"
+#import "CDRExampleGroup.h"
+#import "CDRSymbolicator.h"
+
+using namespace Cedar::Matchers;
+
+#if !__arm__
+SPEC_BEGIN(CDRSymbolicatorSpec)
+
+describe(@"CDRSymbolicator", ^{
+ __block CDRExample *example;
+ __block CDRExampleGroup *group;
+
+ void (^verifyFileNameAndLineNumber)(CDRExampleBase *, NSString *, int) =
+ ^(CDRExampleBase *b, NSString *fileName, int lineNumber) {
+ NSNumber *address = [NSNumber numberWithUnsignedInteger:b.stackAddress];
+ NSArray *addresses = [NSArray arrayWithObject:address];
+
+ CDRSymbolicator *symbolicator = [[CDRSymbolicator alloc] init];
+ [symbolicator symbolicateAddresses:addresses];
+
+ [[symbolicator fileNameForStackAddress:b.stackAddress] hasSuffix:fileName] should be_truthy;
+ [symbolicator lineNumberForStackAddress:b.stackAddress] should equal(lineNumber);
+ [symbolicator release];
+ };
+
+ it(@"identifies file name and line number of an it", ^{
+ example = it(@"it", ^{});
+ verifyFileNameAndLineNumber(example, @"CDRSymbolicatorSpec.mm", __LINE__-1);
+ });
+
+ it(@"identifies file name line number of a describe", ^{
+ group = describe(@"describe", ^{});
+ verifyFileNameAndLineNumber(group, @"CDRSymbolicatorSpec.mm", __LINE__-1);
+ });
+
+ it(@"identifies file name line number of a context", ^{
+ group = context(@"context", ^{});
+ verifyFileNameAndLineNumber(group, @"CDRSymbolicatorSpec.mm", __LINE__-1);
+ });
+
+ it(@"identifies file name line number of a nested it", ^{
+ describe(@"describe", ^{
+ example = it(@"it", ^{});
+ });
+ verifyFileNameAndLineNumber(example, @"CDRSymbolicatorSpec.mm", __LINE__-2);
+ });
+
+ it(@"identifies file name line number of a nested describe", ^{
+ describe(@"describe", ^{
+ group = describe(@"describe", ^{});
+ });
+ verifyFileNameAndLineNumber(group, @"CDRSymbolicatorSpec.mm", __LINE__-2);
+ });
+
+ it(@"identifies file name line number of a nested context", ^{
+ describe(@"describe", ^{
+ group = context(@"context", ^{});
+ });
+ verifyFileNameAndLineNumber(group, @"CDRSymbolicatorSpec.mm", __LINE__-2);
+ });
+});
+
+SPEC_END
+#endif
Please sign in to comment.
Something went wrong with that request. Please try again.