blob: 5a10fe7a9e01a5b2765c220174c801771a854541 [file] [log] [blame]
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -emit-library -o %t/libGetImageNameHelper.dylib -emit-module %S/Inputs/class_getImageName-helper.swift -Xlinker -install_name -Xlinker @executable_path/libGetImageNameHelper.dylib
// RUN: %target-codesign %t/libGetImageNameHelper.dylib
// RUN: %target-build-swift -g %s -I %t -o %t/main -L %t -lGetImageNameHelper
// RUN: %target-run %t/main %t/libGetImageNameHelper.dylib
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Darwin
import ObjectiveC
import GetImageNameHelper
import StdlibUnittest
func check(_ cls: AnyClass, in library: String) {
guard let imageName = class_getImageName(cls) else {
expectUnreachable("could not find image for \(cls)")
return
}
expectTrue(String(cString: imageName).hasSuffix(library),
"wrong library for \(cls)")
}
var newOSButCannotUseObjCRuntimeHook = false
if #available(macOS 10.14, iOS 12, tvOS 12, watchOS 5, *) {
// The only place these tests will fail is on early versions of the 2018 OSs.
// The final versions will have 'objc_setHook_getImageName'; anything earlier
// will be handled by manually overwriting the original implementation of
// 'class_getImageName'.
newOSButCannotUseObjCRuntimeHook =
(nil == dlsym(UnsafeMutableRawPointer(bitPattern: -2),
"objc_setHook_getImageName"))
}
var testSuite = TestSuite("class_getImageName")
testSuite.test("Simple") {
check(SimpleSwiftObject.self, in: "libGetImageNameHelper.dylib")
check(SimpleNSObject.self, in: "libGetImageNameHelper.dylib")
}
testSuite.test("Generic")
.skip(.custom({ newOSButCannotUseObjCRuntimeHook },
reason: "hook for class_getImageName not present"))
.code {
check(GenericSwiftObject<Int>.self, in: "libGetImageNameHelper.dylib")
check(GenericSwiftObject<NSObject>.self, in: "libGetImageNameHelper.dylib")
check(GenericNSObject<Int>.self, in: "libGetImageNameHelper.dylib")
check(GenericNSObject<NSObject>.self, in: "libGetImageNameHelper.dylib")
}
testSuite.test("GenericAncestry")
.skip(.custom({ newOSButCannotUseObjCRuntimeHook },
reason: "hook for class_getImageName not present"))
.code {
check(GenericAncestrySwiftObject.self, in: "libGetImageNameHelper.dylib")
check(GenericAncestryNSObject.self, in: "libGetImageNameHelper.dylib")
}
testSuite.test("Resilient") {
check(ResilientFieldSwiftObject.self, in: "libGetImageNameHelper.dylib")
check(ResilientFieldNSObject.self, in: "libGetImageNameHelper.dylib")
}
testSuite.test("ObjC") {
check(NSObject.self, in: "libobjc.A.dylib")
}
testSuite.test("KVO/Simple") {
// We use object_getClass in this test to not look through KVO's artificial
// subclass.
let obj = SimpleNSObject()
autoreleasepool {
let observation = obj.observe(\.observableName) { _, _ in }
withExtendedLifetime(observation) {
let theClass = object_getClass(obj)
precondition(theClass !== SimpleNSObject.self, "no KVO subclass?")
expectNil(class_getImageName(theClass),
"should match what happens with NSObject (below)")
}
}
}
testSuite.test("KVO/GenericAncestry") {
// We use object_getClass in this test to not look through KVO's artificial
// subclass.
let obj = GenericAncestryNSObject()
autoreleasepool {
let observation = obj.observe(\.observableName) { _, _ in }
withExtendedLifetime(observation) {
let theClass = object_getClass(obj)
precondition(theClass !== GenericAncestryNSObject.self, "no KVO subclass?")
expectNil(class_getImageName(theClass),
"should match what happens with NSObject (below)")
}
}
}
testSuite.test("KVO/ObjC") {
// We use object_getClass in this test to not look through KVO's artificial
// subclass.
let obj = NSObject()
autoreleasepool {
let observation = obj.observe(\.description) { _, _ in }
withExtendedLifetime(observation) {
let theClass = object_getClass(obj)
precondition(theClass !== NSObject.self, "no KVO subclass?")
expectNil(class_getImageName(theClass),
"should match what happens with the Swift objects (above)")
}
}
}
testSuite.test("dynamic") {
let newClass: AnyClass = objc_allocateClassPair(/*superclass*/nil,
"CompletelyDynamic",
/*extraBytes*/0)!
objc_registerClassPair(newClass)
// We don't actually care what the result is; we just need to not crash.
_ = class_getImageName(newClass)
}
testSuite.test("nil") {
// The ObjC runtime should handle this before it even gets to Swift's custom
// implementation, but just in case.
expectNil(class_getImageName(nil))
}
runAllTests()