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

Allow SLAssert methods to be called from non SLTest subclass methods #217

Merged
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
27 changes: 18 additions & 9 deletions Sources/Classes/SLTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@
@param filename A filename, i.e. the last component of the `__FILE__` macro's expansion.
@param lineNumber A line number, i.e. the `__LINE__` macro's expansion.
*/
- (void)recordLastKnownFile:(const char *)filename line:(int)lineNumber;
+ (void)recordLastKnownFile:(const char *)filename line:(int)lineNumber;

/**
Records the current filename and line number and returns its argument.
Expand All @@ -404,23 +404,32 @@
UIAutomation element corresponding to the wrapped `SLUIAElement`."
*/
#define UIAElement(slElement) ({ \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
slElement; \
})

#pragma mark - Test Assertions
/**
The SLAssert* class of methods should only be used from test setup, teardown,
or execution methods as well as those methods called from within.

@warning If you use an assertion inside a dispatch block--if your test case
dispatches to the main queue, for instance--you must wrap the assertion in a
try-catch block and re-throw the exception it generates (if any) outside the
dispatch block. Otherwise, the tests will abort with an unhandled exception.
*/

/**
Fails the test case if the specified expression is false.

@param expression The expression to test.
@param failureDescription A format string specifying the error message
to be logged if the test fails. Can be `nil`.
@param ... (Optional) A comma-separated list of arguments to substitute into
`failureDescription`.
*/
#define SLAssertTrue(expression, failureDescription, ...) do { \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
BOOL __result = !!(expression); \
if (!__result) { \
NSString *__reason = [NSString stringWithFormat:@"\"%@\" should be true.%@", \
Expand Down Expand Up @@ -471,7 +480,7 @@
to be logged if the test fails. Can be `nil`.
*/
#define SLAssertTrueWithTimeout(expression, timeout, failureDescription, ...) do {\
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
\
if (!SLWaitUntilTrue(expression, timeout)) { \
NSString *reason = [NSString stringWithFormat:@"\"%@\" did not become true within %g seconds.%@", \
Expand Down Expand Up @@ -526,7 +535,7 @@
`failureDescription`.
*/
#define SLAssertFalse(expression, failureDescription, ...) do { \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
BOOL __result = !!(expression); \
if (__result) { \
NSString *__reason = [NSString stringWithFormat:@"\"%@\" should be false.%@", \
Expand All @@ -545,7 +554,7 @@
`failureDescription`.
*/
#define SLAssertThrows(expression, failureDescription, ...) do { \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
BOOL __caughtException = NO; \
@try { \
(expression); \
Expand All @@ -572,7 +581,7 @@
`failureDescription`.
*/
#define SLAssertThrowsNamed(expression, exceptionName, failureDescription, ...) do { \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
BOOL __caughtException = NO; \
@try { \
(expression); \
Expand Down Expand Up @@ -608,7 +617,7 @@
`failureDescription`.
*/
#define SLAssertNoThrow(expression, failureDescription, ...) do { \
[self recordLastKnownFile:__FILE__ line:__LINE__]; \
[SLTest recordLastKnownFile:__FILE__ line:__LINE__]; \
@try { \
(expression); \
} \
Expand Down
30 changes: 15 additions & 15 deletions Sources/Classes/SLTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
const NSTimeInterval SLWaitUntilTrueRetryDelay = 0.25;


@implementation SLTest {
NSString *_lastKnownFilename;
int _lastKnownLineNumber;
}
@implementation SLTest

static NSString *__lastKnownFilename;
static int __lastKnownLineNumber;

+ (NSSet *)allTests {
NSMutableSet *tests = [[NSMutableSet alloc] init];
Expand Down Expand Up @@ -264,7 +264,7 @@ - (BOOL)runAndReportNumExecuted:(NSUInteger *)numCasesExecuted

// clear call site information, so at the least it won't be reused between test cases
// (though we can't guarantee it won't be reused within a test case)
[self clearLastKnownCallSite];
[SLTest clearLastKnownCallSite];

BOOL caseFailed = NO, failureWasExpected = NO;
@try {
Expand Down Expand Up @@ -340,34 +340,34 @@ - (void)wait:(NSTimeInterval)interval {
[NSThread sleepForTimeInterval:interval];
}

- (void)recordLastKnownFile:(const char *)filename line:(int)lineNumber {
_lastKnownFilename = [@(filename) lastPathComponent];
_lastKnownLineNumber = lineNumber;
+ (void)recordLastKnownFile:(const char *)filename line:(int)lineNumber {
__lastKnownFilename = [@(filename) lastPathComponent];
__lastKnownLineNumber = lineNumber;
}

- (void)clearLastKnownCallSite {
_lastKnownFilename = nil;
_lastKnownLineNumber = 0;
+ (void)clearLastKnownCallSite {
__lastKnownFilename = nil;
__lastKnownLineNumber = 0;
}

- (NSException *)exceptionByAddingFileInfo:(NSException *)exception {
// Only use the call site information if we have information
// and if the exception was thrown by `SLTest` or `SLUIAElement`,
// where the information was likely to have been recorded by an assertion or UIAElement macro.
// Otherwise it is likely stale.
if (_lastKnownFilename &&
if (__lastKnownFilename &&
([[exception name] hasPrefix:SLTestExceptionNamePrefix] ||
[[exception name] hasPrefix:SLUIAElementExceptionNamePrefix])) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
userInfo[SLLoggerExceptionFilenameKey] = _lastKnownFilename;
userInfo[SLLoggerExceptionLineNumberKey] = @(_lastKnownLineNumber);
userInfo[SLLoggerExceptionFilenameKey] = __lastKnownFilename;
userInfo[SLLoggerExceptionLineNumberKey] = @(__lastKnownLineNumber);

exception = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo];
}

// Regardless of whether we used it or not,
// call site info is now stale
[self clearLastKnownCallSite];
[SLTest clearLastKnownCallSite];

return exception;
}
Expand Down