Skip to content

Commit b0d8fce

Browse files
committed
Extract swizzleSelectors function
1 parent 897ffb5 commit b0d8fce

1 file changed

Lines changed: 25 additions & 26 deletions

File tree

Sources/Nimble/Adapters/ObjectiveC/XCTestObservationCenter+Register.m

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,14 @@
22
#import <XCTest/XCTest.h>
33
#import <objc/runtime.h>
44

5-
#pragma mark - Private
6-
7-
@interface XCTestObservationCenter (Private)
8-
- (void)_addLegacyTestObserver:(id)observer;
9-
@end
10-
11-
@implementation XCTestObservationCenter (Register)
12-
13-
/// Uses objc method swizzling to register `CurrentTestCaseTracker` as a test observer. This is necessary
14-
/// because Xcode 7.3 introduced timing issues where if a custom `XCTestObservation` is registered too early
15-
/// it suppresses all console output (generated by `XCTestLog`), breaking any tools that depend on this output.
16-
/// This approach waits to register our custom test observer until XCTest adds its first "legacy" observer,
17-
/// falling back to registering after the first normal observer if this private method ever changes.
18-
+ (void)load {
19-
if (class_getInstanceMethod([self class], @selector(_addLegacyTestObserver:))) {
20-
// Swizzle -_addLegacyTestObserver:
21-
[self swizzleSelector:@selector(_addLegacyTestObserver:) withSelector:@selector(NMB_original__addLegacyTestObserver:)];
22-
} else {
23-
// Swizzle -addTestObserver:, only if -_addLegacyTestObserver: is not implemented
24-
[self swizzleSelector:@selector(addTestObserver:) withSelector:@selector(NMB_original_addTestObserver:)];
25-
}
26-
}
27-
285
#pragma mark - Method Swizzling
296

307
/// Swaps the implementations between two instance methods.
318
///
9+
/// @param class The class containing `originalSelector`.
3210
/// @param originalSelector Original method to replace.
3311
/// @param replacementSelector Replacement method.
34-
+ (void)swizzleSelector:(SEL)originalSelector withSelector:(SEL)replacementSelector {
35-
Class class = [self class];
36-
12+
void swizzleSelectors(Class class, SEL originalSelector, SEL replacementSelector) {
3713
Method originalMethod = class_getInstanceMethod(class, originalSelector);
3814
Method replacementMethod = class_getInstanceMethod(class, replacementSelector);
3915

@@ -53,6 +29,29 @@ + (void)swizzleSelector:(SEL)originalSelector withSelector:(SEL)replacementSelec
5329
}
5430
}
5531

32+
#pragma mark - Private
33+
34+
@interface XCTestObservationCenter (Private)
35+
- (void)_addLegacyTestObserver:(id)observer;
36+
@end
37+
38+
@implementation XCTestObservationCenter (Register)
39+
40+
/// Uses objc method swizzling to register `CurrentTestCaseTracker` as a test observer. This is necessary
41+
/// because Xcode 7.3 introduced timing issues where if a custom `XCTestObservation` is registered too early
42+
/// it suppresses all console output (generated by `XCTestLog`), breaking any tools that depend on this output.
43+
/// This approach waits to register our custom test observer until XCTest adds its first "legacy" observer,
44+
/// falling back to registering after the first normal observer if this private method ever changes.
45+
+ (void)load {
46+
if (class_getInstanceMethod([self class], @selector(_addLegacyTestObserver:))) {
47+
// Swizzle -_addLegacyTestObserver:
48+
swizzleSelectors([self class], @selector(_addLegacyTestObserver:), @selector(NMB_original__addLegacyTestObserver:));
49+
} else {
50+
// Swizzle -addTestObserver:, only if -_addLegacyTestObserver: is not implemented
51+
swizzleSelectors([self class], @selector(addTestObserver:), @selector(NMB_original_addTestObserver:));
52+
}
53+
}
54+
5655
#pragma mark - Replacement Methods
5756

5857
/// Registers `CurrentTestCaseTracker` as a test observer after `XCTestLog` has been added.

0 commit comments

Comments
 (0)