// 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-codesign %t/main // 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.self, in: "libGetImageNameHelper.dylib") check(GenericSwiftObject.self, in: "libGetImageNameHelper.dylib") check(GenericNSObject.self, in: "libGetImageNameHelper.dylib") check(GenericNSObject.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*/NSObject.self, "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()