Files
swift-mirror/test/Interpreter/objc_class_properties.swift
Doug Gregor def86ce402 Revert "[irgen] Force emission of objc class refs for non-foreign clang objc classes whose metadata we use."
This reverts commit 8247525471. While
correct, it has uncovered several issues in existing code bases that
need to be sorted out before we can land it again.
Fixes rdar://problem/57846390.
2020-01-11 21:46:42 -08:00

244 lines
5.7 KiB
Swift

// RUN: %empty-directory(%t)
// RUN: %clang %target-cc-options -isysroot %sdk -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o
// RUN: %target-build-swift -I %S/Inputs/ObjCClasses/ %t/ObjCClasses.o %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Foundation
import StdlibUnittest
import ObjCClasses
class SwiftClass : ProtoWithClassProperty {
static var getCount = 0
static var setCount = 0
private static var _value: CInt = 0
@objc class func reset() {
getCount = 0
setCount = 0
_value = 0
}
@objc class var value: CInt {
get {
getCount += 1
return _value
}
set {
setCount += 1
_value = newValue
}
}
@objc class var optionalClassProp: Bool {
return true
}
}
class Subclass : ClassWithClassProperty {
static var getCount = 0
static var setCount = 0
override class func reset() {
getCount = 0
setCount = 0
super.reset()
}
override class var value: CInt {
get {
getCount += 1
return super.value
}
set {
setCount += 1
super.value = newValue
}
}
override class var optionalClassProp: Bool {
return true
}
}
var ClassProperties = TestSuite("ClassProperties")
ClassProperties.test("direct") {
ClassWithClassProperty.reset()
expectEqual(0, ClassWithClassProperty.value)
ClassWithClassProperty.value = 4
expectEqual(4, ClassWithClassProperty.value)
Subclass.reset()
expectEqual(0, Subclass.value)
Subclass.value = 4
expectEqual(4, Subclass.value)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testExistential(_ e: ProtoWithClassProperty.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("existentials") {
testExistential(ClassWithClassProperty.self)
testExistential(ObjCSubclassWithClassProperty.self)
testExistential(SwiftClass.self)
expectEqual(2, SwiftClass.getCount)
expectEqual(1, SwiftClass.setCount)
testExistential(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testGeneric<T: ProtoWithClassProperty>(_ e: T.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("generics") {
testGeneric(ClassWithClassProperty.self)
testGeneric(ObjCSubclassWithClassProperty.self)
testGeneric(SwiftClass.self)
expectEqual(2, SwiftClass.getCount)
expectEqual(1, SwiftClass.setCount)
testGeneric(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testInheritance(_ e: ClassWithClassProperty.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("inheritance") {
testInheritance(ClassWithClassProperty.self)
testInheritance(ObjCSubclassWithClassProperty.self)
testInheritance(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testInheritanceGeneric<T: ClassWithClassProperty>(_ e: T.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("inheritance/generic") {
testInheritanceGeneric(ClassWithClassProperty.self)
testInheritanceGeneric(ObjCSubclassWithClassProperty.self)
testInheritanceGeneric(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
ClassProperties.test("optionalProp") {
let noProp: ProtoWithClassProperty.Type = ClassWithClassProperty.self
expectNil(noProp.optionalClassProp)
let hasProp: ProtoWithClassProperty.Type = Subclass.self
expectNotNil(hasProp.optionalClassProp)
expectEqual(true, hasProp.optionalClassProp!)
let hasOwnProp: ProtoWithClassProperty.Type = SwiftClass.self
expectNotNil(hasOwnProp.optionalClassProp)
expectEqual(true, hasOwnProp.optionalClassProp!)
let hasPropObjC: ProtoWithClassProperty.Type = ObjCSubclassWithClassProperty.self
expectNotNil(hasPropObjC.optionalClassProp)
expectEqual(true, hasPropObjC.optionalClassProp!)
}
class NamingConflictSubclass : PropertyNamingConflict {
override var prop: Any? { return nil }
override class var prop: Any? { return NamingConflictSubclass() }
}
ClassProperties.test("namingConflict") {
let obj = PropertyNamingConflict()
expectTrue(obj === obj.prop.map { $0 as AnyObject })
expectNil(type(of: obj).prop)
expectNil(PropertyNamingConflict.prop)
let sub = NamingConflictSubclass()
expectNil(sub.prop)
expectNotNil(type(of: sub).prop)
expectNotNil(NamingConflictSubclass.prop)
}
extension NamingConflictSubclass : PropertyNamingConflictProto {
var protoProp: Any? {
get { return self }
set {}
}
class var protoProp: Any? {
get { return nil }
set {}
}
}
ClassProperties.test("namingConflict/protocol") {
let obj: PropertyNamingConflictProto = NamingConflictSubclass()
expectTrue(obj === obj.protoProp.map { $0 as AnyObject })
expectNil(type(of: obj).protoProp)
let type: PropertyNamingConflictProto.Type = NamingConflictSubclass.self
expectNil(type.protoProp)
}
var global1: Int = 0
var global2: Int = 0
class Steak : NSObject {
@objc override var thickness: Int {
get { return global1 } set { global1 = newValue }
}
}
extension NSObject : HasThickness {
@objc var thickness: Int { get { return global2 } set { global2 = newValue } }
}
protocol HasThickness : class {
var thickness: Int { get set }
}
ClassProperties.test("dynamicOverride") {
// Calls NSObject.thickness
NSObject().thickness += 1
// Calls Steak.thickness
(Steak() as NSObject).thickness += 1
Steak().thickness += 1
(Steak() as HasThickness).thickness += 1
expectEqual(3, global1)
expectEqual(1, global2)
}
runAllTests()