Skip to content

Commit

Permalink
[refactoring] Re-implement qck_enumerateSubclasses in Swift
Browse files Browse the repository at this point in the history
  • Loading branch information
ikesyo committed Apr 18, 2019
1 parent 8a4f0e5 commit 984890d
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 53 deletions.
1 change: 0 additions & 1 deletion Quick.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Pod::Spec.new do |s|
]

s.exclude_files = [
'Sources/Quick/Configuration/QuickConfiguration.swift',
'Sources/Quick/QuickSpec.swift',
'Sources/Quick/QuickMain.swift',
]
Expand Down
6 changes: 6 additions & 0 deletions Quick.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@
CD582D762264C137008F7CE6 /* QuickSpecRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD582D722264C137008F7CE6 /* QuickSpecRunner.swift */; };
CD582D772264C137008F7CE6 /* QuickSpecRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD582D722264C137008F7CE6 /* QuickSpecRunner.swift */; };
CD582D782264C137008F7CE6 /* QuickSpecRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD582D722264C137008F7CE6 /* QuickSpecRunner.swift */; };
CDE5BDFD2268CE95006E2F66 /* QuickConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD261AC81DEC8B0000A8863C /* QuickConfiguration.swift */; };
CDE5BDFE2268CE96006E2F66 /* QuickConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD261AC81DEC8B0000A8863C /* QuickConfiguration.swift */; };
CDE5BDFF2268CE97006E2F66 /* QuickConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD261AC81DEC8B0000A8863C /* QuickConfiguration.swift */; };
CE175D4E1E8D6B4900EB5E84 /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE175D4D1E8D6B4900EB5E84 /* Behavior.swift */; };
CE175D4F1E8D6B4900EB5E84 /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE175D4D1E8D6B4900EB5E84 /* Behavior.swift */; };
CE175D501E8D6B4900EB5E84 /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE175D4D1E8D6B4900EB5E84 /* Behavior.swift */; };
Expand Down Expand Up @@ -1449,6 +1452,7 @@
CE175D501E8D6B4900EB5E84 /* Behavior.swift in Sources */,
CE590E1F1C431FE400253D19 /* QuickTestSuite.swift in Sources */,
1F118D091BDCA536005013A2 /* QuickSpec.m in Sources */,
CDE5BDFF2268CE97006E2F66 /* QuickConfiguration.swift in Sources */,
1F118D011BDCA536005013A2 /* ExampleHooks.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1534,6 +1538,7 @@
CE175D4F1E8D6B4900EB5E84 /* Behavior.swift in Sources */,
CE590E1A1C431FE300253D19 /* QuickTestSuite.swift in Sources */,
DA3124E719FCAEE8002858A7 /* DSL.swift in Sources */,
CDE5BDFE2268CE96006E2F66 /* QuickConfiguration.swift in Sources */,
DA6B30191A4DB0D500FFB148 /* Filter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1659,6 +1664,7 @@
CE175D4E1E8D6B4900EB5E84 /* Behavior.swift in Sources */,
34F375AB19515CA700CE1B99 /* Example.swift in Sources */,
DA3124E619FCAEE8002858A7 /* DSL.swift in Sources */,
CDE5BDFD2268CE95006E2F66 /* QuickConfiguration.swift in Sources */,
DA6B30181A4DB0D500FFB148 /* Filter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
45 changes: 26 additions & 19 deletions Sources/Quick/Configuration/QuickConfiguration.swift
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
import Foundation
import XCTest

// NOTE: This file is not intended to be included in the Xcode project or CocoaPods.
// It is picked up by the Swift Package Manager during its build process.

#if SWIFT_PACKAGE

open class QuickConfiguration: NSObject {
open class func configure(_ configuration: Configuration) {}
}

#endif

#if canImport(Darwin)

internal func qck_enumerateSubclasses<T: AnyObject>(_ klass: T.Type, block: (T.Type) -> Void) {
var classesCount = objc_getClassList(nil, 0)
extension QuickConfiguration {

guard classesCount > 0 else {
return
}
/// Finds all direct subclasses of QuickConfiguration and passes them to the block provided.
/// The classes are iterated over in the order that objc_getClassList returns them.
///
/// - parameter block: A block that takes a QuickConfiguration.Type.
/// This block will be executed once for each subclass of QuickConfiguration.
@objc static func enumerateSubclasses(_ block: (QuickConfiguration.Type) -> Void) {
var classesCount = objc_getClassList(nil, 0)

let classes = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(classesCount))
classesCount = objc_getClassList(AutoreleasingUnsafeMutablePointer(classes), classesCount)
guard classesCount > 0 else {
return
}

var subclass: AnyClass!
for i in 0..<classesCount {
subclass = classes[Int(i)]
let classes = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(classesCount))
defer { free(classes) }

guard let superclass = class_getSuperclass(subclass), superclass == klass else { continue }
classesCount = objc_getClassList(AutoreleasingUnsafeMutablePointer(classes), classesCount)

block(subclass as! T.Type) // swiftlint:disable:this force_cast
}
for i in 0..<classesCount {
guard
let subclass = classes[Int(i)],
let superclass = class_getSuperclass(subclass),
superclass == QuickConfiguration.self
else { continue }

free(classes)
// swiftlint:disable:next force_cast
block(subclass as! QuickConfiguration.Type)
}
}
}

#endif

#endif
2 changes: 1 addition & 1 deletion Sources/Quick/QuickSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ open class QuickSpec: QuickSpecBase {
if !world.isConfigurationFinalized {
// Perform all configurations (ensures that shared examples have been discovered)
world.configure { configuration in
qck_enumerateSubclasses(QuickConfiguration.self) { configurationClass in
QuickConfiguration.enumerateSubclasses { configurationClass in
configurationClass.configure(configuration)
}
}
Expand Down
34 changes: 2 additions & 32 deletions Sources/QuickObjectiveC/Configuration/QuickConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,6 @@
#import <Quick/Quick-Swift.h>
#endif

typedef void (^QCKClassEnumerationBlock)(Class klass);

/**
Finds all direct subclasses of the given class and passes them to the block provided.
The classes are iterated over in the order that objc_getClassList returns them.
@param klass The base class to find subclasses of.
@param block A block that takes a Class. This block will be executed once for each subclass of klass.
*/
void qck_enumerateSubclasses(Class klass, QCKClassEnumerationBlock block) {
Class *classes = NULL;
int classesCount = objc_getClassList(NULL, 0);

if (classesCount > 0) {
classes = (Class *)calloc(sizeof(Class), classesCount);
classesCount = objc_getClassList(classes, classesCount);

Class subclass, superclass;
for(int i = 0; i < classesCount; i++) {
subclass = classes[i];
superclass = class_getSuperclass(subclass);
if (superclass == klass && block) {
block(subclass);
}
}

free(classes);
}
}

@implementation QuickConfiguration

#pragma mark - Object Lifecycle
Expand Down Expand Up @@ -71,11 +41,11 @@ + (void)initialize {
// manually calls +[QuickConfiguration initialize].
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
qck_enumerateSubclasses([QuickConfiguration class], ^(__unsafe_unretained Class klass) {
[QuickConfiguration enumerateSubclasses:^(Class _Nonnull __unsafe_unretained klass) {
[[World sharedWorld] configure:^(Configuration *configuration) {
[klass configure:configuration];
}];
});
}];
[[World sharedWorld] finalizeConfiguration];
});
}
Expand Down

0 comments on commit 984890d

Please sign in to comment.