Skip to content

Commit f9f3d46

Browse files
authored
Merge pull request #2231 from millenomi/bundle-for-anyclass
Parity: Bundle(for: AnyClass)
2 parents a3ab9e1 + 55942f9 commit f9f3d46

File tree

5 files changed

+93
-34
lines changed

5 files changed

+93
-34
lines changed

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ CF_EXPORT _Nullable CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef _Null_uns
414414
CF_CROSS_PLATFORM_EXPORT CFStringRef _Nullable _CFBundleCopyExecutablePath(CFBundleRef bundle);
415415
CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFHSBundles(void);
416416
CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFreestandingBundles(void);
417+
CF_CROSS_PLATFORM_EXPORT CFStringRef _Nullable _CFBundleCopyLoadedImagePathForAddress(const void *p);
418+
417419
CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void);
418420

419421
CF_CROSS_PLATFORM_EXPORT void *_Nullable _CFURLCopyResourceInfo(CFURLRef url);

CoreFoundation/PlugIn.subproj/CFBundle_Binary.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,11 @@ CF_PRIVATE void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef sym
746746

747747
#endif /* BINARY_SUPPORT_DLL */
748748

749+
// For Swift:
750+
CF_CROSS_PLATFORM_EXPORT CFStringRef _CFBundleCopyLoadedImagePathForAddress(const void *p) {
751+
return _CFBundleCopyLoadedImagePathForPointer((void *)p);
752+
}
753+
749754
CF_PRIVATE CFStringRef _CFBundleCopyLoadedImagePathForPointer(void *p) {
750755
CFStringRef imagePath = NULL;
751756
#if defined(BINARY_SUPPORT_DYLD)

Foundation/Bundle.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
import CoreFoundation
1111

12+
@_silgen_name("swift_getTypeContextDescriptor")
13+
private func _getTypeContextDescriptor(of cls: AnyClass) -> UnsafeRawPointer
14+
1215
open class Bundle: NSObject {
1316
private var _bundle : CFBundle!
1417

@@ -100,9 +103,38 @@ open class Bundle: NSObject {
100103
self.init(path: url.path)
101104
}
102105

106+
#if os(Windows)
107+
@available(Windows, deprecated, message: "Not yet implemented.")
103108
public init(for aClass: AnyClass) {
104109
NSUnimplemented()
105110
}
111+
#else
112+
public init(for aClass: AnyClass) {
113+
let pointerInImageOfClass = _getTypeContextDescriptor(of: aClass)
114+
guard let imagePath = _CFBundleCopyLoadedImagePathForAddress(pointerInImageOfClass)?._swiftObject else {
115+
_bundle = CFBundleGetMainBundle()
116+
return
117+
}
118+
119+
let path = (try? FileManager.default._canonicalizedPath(toFileAtPath: imagePath)) ?? imagePath
120+
121+
let url = URL(fileURLWithPath: path)
122+
if Bundle.main.executableURL == url {
123+
_bundle = CFBundleGetMainBundle()
124+
return
125+
}
126+
127+
for bundle in Bundle.allBundlesRegardlessOfType {
128+
if bundle.executableURL == url {
129+
_bundle = bundle._bundle
130+
return
131+
}
132+
}
133+
134+
let bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(kCFAllocatorSystemDefault, url._cfObject)?.takeRetainedValue()
135+
_bundle = bundle ?? CFBundleGetMainBundle()
136+
}
137+
#endif
106138

107139
public init?(identifier: String) {
108140
super.init()
@@ -388,5 +420,15 @@ open class Bundle: NSObject {
388420
let architectures = CFBundleCopyExecutableArchitectures(_bundle)!
389421
return architectures._swiftObject.map() { $0 as! NSNumber }
390422
}
423+
424+
open override func isEqual(_ object: Any?) -> Bool {
425+
guard let bundle = object as? Bundle else { return false }
426+
return CFEqual(_bundle, bundle._bundle)
427+
}
428+
429+
open override var hash: Int {
430+
return Int(bitPattern: CFHash(_bundle))
431+
}
391432
}
392433

434+

TestFoundation/TestBundle.swift

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -338,31 +338,6 @@ class BundlePlayground {
338338
}
339339

340340
class TestBundle : XCTestCase {
341-
342-
static var allTests: [(String, (TestBundle) -> () throws -> Void)] {
343-
var tests: [(String, (TestBundle) -> () throws -> Void)] = [
344-
("test_paths", test_paths),
345-
("test_resources", test_resources),
346-
("test_infoPlist", test_infoPlist),
347-
("test_localizations", test_localizations),
348-
("test_URLsForResourcesWithExtension", test_URLsForResourcesWithExtension),
349-
("test_bundleLoad", test_bundleLoad),
350-
("test_bundleLoadWithError", test_bundleLoadWithError),
351-
("test_bundleWithInvalidPath", test_bundleWithInvalidPath),
352-
("test_bundlePreflight", test_bundlePreflight),
353-
("test_bundleFindExecutable", test_bundleFindExecutable),
354-
("test_bundleFindAuxiliaryExecutables", test_bundleFindAuxiliaryExecutables),
355-
("test_bundleReverseBundleLookup", test_bundleReverseBundleLookup),
356-
]
357-
358-
#if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT
359-
tests.append(contentsOf: [
360-
("test_mainBundleExecutableURL", test_mainBundleExecutableURL),
361-
])
362-
#endif
363-
364-
return tests
365-
}
366341

367342
func test_paths() {
368343
let bundle = testBundle()
@@ -578,4 +553,34 @@ class TestBundle : XCTestCase {
578553
#endif
579554
}
580555
#endif
556+
557+
func test_bundleForClass() {
558+
XCTAssertEqual(testBundle(), Bundle(for: type(of: self)))
559+
}
560+
561+
static var allTests: [(String, (TestBundle) -> () throws -> Void)] {
562+
var tests: [(String, (TestBundle) -> () throws -> Void)] = [
563+
("test_paths", test_paths),
564+
("test_resources", test_resources),
565+
("test_infoPlist", test_infoPlist),
566+
("test_localizations", test_localizations),
567+
("test_URLsForResourcesWithExtension", test_URLsForResourcesWithExtension),
568+
("test_bundleLoad", test_bundleLoad),
569+
("test_bundleLoadWithError", test_bundleLoadWithError),
570+
("test_bundleWithInvalidPath", test_bundleWithInvalidPath),
571+
("test_bundlePreflight", test_bundlePreflight),
572+
("test_bundleFindExecutable", test_bundleFindExecutable),
573+
("test_bundleFindAuxiliaryExecutables", test_bundleFindAuxiliaryExecutables),
574+
("test_bundleReverseBundleLookup", test_bundleReverseBundleLookup),
575+
("test_bundleForClass", testExpectedToFailOnWindows(test_bundleForClass, "Functionality not yet implemented on Windows. SR-XXXX")),
576+
]
577+
578+
#if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT
579+
tests.append(contentsOf: [
580+
("test_mainBundleExecutableURL", test_mainBundleExecutableURL),
581+
])
582+
#endif
583+
584+
return tests
585+
}
581586
}

TestFoundation/Utilities.swift

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -498,14 +498,11 @@ func shouldAttemptXFailTests(_ reason: String) -> Bool {
498498
}
499499

500500
func shouldAttemptWindowsXFailTests(_ reason: String) -> Bool {
501-
var isOSWindows: Bool = false
502-
#if os(Windows)
503-
isOSWindows = true
504-
#endif
505-
506-
if !isOSWindows || shouldRunXFailTests { return true }
507-
try? FileHandle.standardError.write(contentsOf: Data("warning: Skipping test expected to fail with reason '\(reason)'\n".utf8))
508-
return false
501+
#if os(Windows)
502+
return shouldAttemptXFailTests(reason)
503+
#else
504+
return true
505+
#endif
509506
}
510507

511508
func appendTestCaseExpectedToFail<T: XCTestCase>(_ reason: String, _ allTests: [(String, (T) -> () throws -> Void)], into array: inout [XCTestCaseEntry]) {
@@ -515,7 +512,15 @@ func appendTestCaseExpectedToFail<T: XCTestCase>(_ reason: String, _ allTests: [
515512
}
516513

517514
func testExpectedToFail<T>(_ test: @escaping (T) -> () throws -> Void, _ reason: String) -> (T) -> () throws -> Void {
518-
if shouldAttemptXFailTests(reason) {
515+
testExpectedToFailWithCheck(check: shouldAttemptXFailTests(_:), test, reason)
516+
}
517+
518+
func testExpectedToFailOnWindows<T>(_ test: @escaping (T) -> () throws -> Void, _ reason: String) -> (T) -> () throws -> Void {
519+
testExpectedToFailWithCheck(check: shouldAttemptWindowsXFailTests(_:), test, reason)
520+
}
521+
522+
func testExpectedToFailWithCheck<T>(check: (String) -> Bool, _ test: @escaping (T) -> () throws -> Void, _ reason: String) -> (T) -> () throws -> Void {
523+
if check(reason) {
519524
return test
520525
} else {
521526
return { _ in return { } }

0 commit comments

Comments
 (0)