//===--- Mirror.swift -----------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift // // RUN: if [ %target-runtime == "objc" ]; \ // RUN: then \ // RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g && \ // RUN: %target-build-swift %t/main.swift %S/Inputs/Mirror/MirrorOther.swift -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \ // RUN: else \ // RUN: %target-build-swift %t/main.swift %S/Inputs/Mirror/MirrorOther.swift -o %t/Mirror; \ // RUN: fi // RUN: %target-codesign %t/Mirror // RUN: %target-run %t/Mirror // REQUIRES: executable_test // REQUIRES: shell // REQUIRES: reflection // rdar://96439408 // UNSUPPORTED: back_deployment_runtime // UNSUPPORTED: use_os_stdlib import StdlibUnittest var mirrors = TestSuite("Mirrors") extension Mirror { public var testDescription: String { let nil_ = "nil" return "[" + children.lazy .map { "\($0.0 ?? nil_): \(String(reflecting: $0.1))" } .joined(separator: ", ") + "]" } } mirrors.test("RandomAccessStructure") { struct Eggs : CustomReflectable { var customMirror: Mirror { return Mirror(self, unlabeledChildren: ["aay", "bee", "cee"]) } } let x = Eggs().customMirror expectEqual("[nil: \"aay\", nil: \"bee\", nil: \"cee\"]", x.testDescription) } let letters = "abcdefghijklmnopqrstuvwxyz " func find(_ substring: String, within domain: String) -> String.Index? { let domainCount = domain.count let substringCount = substring.count if (domainCount < substringCount) { return nil } var sliceStart = domain.startIndex var sliceEnd = domain.index(sliceStart, offsetBy: substringCount) var i = 0 while true { if domain[sliceStart..") { class C : CustomReflectable { var c: UInt = 3 var customMirror: Mirror { return Mirror(self, children: ["sea": c + 1]) } } let c = Mirror(reflecting: C()) expectTrue(c.subjectType == C.self) expectNil(c.superclassMirror) expectEqual(1, c.children.count) expectEqual("sea", c.children.first!.label) expectEqual(4, c.children.first!.value as? UInt) } mirrors.test("class/Plain/Plain") { class A { var a: Int = 1 } class B : A { var b: UInt = 42 } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let bChild = expectNotNil(b.children.first) { expectEqual("b", bChild.label) expectEqual(42, bChild.value as? UInt) } if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) if let aChild = expectNotNil(a.children.first) { expectEqual("a", aChild.label) expectEqual(1, aChild.value as? Int) expectNil(a.superclassMirror) } } } mirrors.test("class/UncustomizedSuper/Synthesized/Implicit") { class A { var a: Int = 1 } class B : A, CustomReflectable { var b: UInt = 42 var customMirror: Mirror { return Mirror(self, children: ["bee": b]) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first?.label) expectNil(a.superclassMirror) } } mirrors.test("class/UncustomizedSuper/Synthesized/Explicit") { class A { var a: Int = 1 } class B : A, CustomReflectable { var b: UInt = 42 var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .generated) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first!.label) expectNil(a.superclassMirror) } } mirrors.test("class/CustomizedSuper/Synthesized") { class A : CustomReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror(self, children: ["aye": a]) } } class B : A { var b: UInt = 42 // This is an unusual case: when writing override on a // customMirror implementation you would typically want to pass // ancestorRepresentation: .customized(super.customMirror) or, in // rare cases, ancestorRepresentation: .Suppressed. However, it // has an expected behavior, which we test here. override var customMirror: Mirror { return Mirror(self, children: ["bee": b]) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first!.label) expectNil(a.superclassMirror) } } #if _runtime(_ObjC) import Foundation import MirrorObjC //===--- ObjC Base Classes ------------------------------------------------===// mirrors.test("class/ObjCPlain/Plain") { class A : NSObject { var a: Int = 1 } class B : A { var b: UInt = 42 } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let bChild = expectNotNil(b.children.first) { expectEqual("b", bChild.label) expectEqual(42, bChild.value as? UInt) } if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) if let aChild = expectNotNil(a.children.first) { expectEqual("a", aChild.label) expectEqual(1, aChild.value as? Int) if let o = expectNotNil(a.superclassMirror) { expectEqual("NSObject", String(reflecting: o.subjectType)) } } } } mirrors.test("class/ObjCUncustomizedSuper/Synthesized/Implicit") { class A : NSObject { var a: Int = 1 } class B : A, CustomReflectable { var b: UInt = 42 var customMirror: Mirror { return Mirror(self, children: ["bee": b]) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first?.label) if let o = expectNotNil(a.superclassMirror) { expectTrue(o.subjectType == NSObject.self) } } } mirrors.test("class/ObjCUncustomizedSuper/Synthesized/Explicit") { class A : NSObject { var a: Int = 1 } class B : A, CustomReflectable { var b: UInt = 42 var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .generated) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first!.label) if let o = expectNotNil(a.superclassMirror) { expectTrue(o.subjectType == NSObject.self) } } } mirrors.test("class/ObjCCustomizedSuper/Synthesized") { class A : DateFormatter, CustomReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror(self, children: ["aye": a]) } } class B : A { var b: UInt = 42 // This is an unusual case: when writing override on a // customMirror implementation you would typically want to pass // ancestorRepresentation: .customized(super.customMirror) or, in // rare cases, ancestorRepresentation: .Suppressed. However, it // has an expected behavior, which we test here. override var customMirror: Mirror { return Mirror(self, children: ["bee": b]) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("a", a.children.first!.label) if let d = expectNotNil(a.superclassMirror) { expectTrue(d.subjectType == DateFormatter.self) if let f = expectNotNil(d.superclassMirror) { expectTrue(f.subjectType == Formatter.self) if let o = expectNotNil(f.superclassMirror) { expectTrue(o.subjectType == NSObject.self) expectNil(o.superclassMirror) } } } } } mirrors.test("ObjC") { // Some Foundation classes lie about their ivars, which would crash // a mirror; make sure we are not automatically exposing ivars of // Objective-C classes from the default mirror implementation. expectEqual(0, Mirror(reflecting: HasIVars()).children.count) } // rdar://problem/39629937 @objc class ObjCClass : NSObject { let value: Int init(value: Int) { self.value = value } override var description: String { return "\(value)" } } struct WrapObjCClassArray { var array: [ObjCClass] } mirrors.test("struct/WrapNSArray") { let nsArray: NSArray = [ ObjCClass(value: 1), ObjCClass(value: 2), ObjCClass(value: 3), ObjCClass(value: 4) ] let s = String(describing: WrapObjCClassArray(array: nsArray as! [ObjCClass])) expectEqual("WrapObjCClassArray(array: [1, 2, 3, 4])", s) } #endif // _runtime(_ObjC) //===--- Weak and Unowned References --------------------------------------===// // Check that Mirror correctly reflects weak/unowned refs to both // Swift and ObjC objects from Swift structs and classes. protocol WeakUnownedTestsP1: AnyObject { func f1() -> Int } protocol WeakUnownedTestsP2 { func f2() -> String } class WeakUnownedSwiftClass: WeakUnownedTestsP1, WeakUnownedTestsP2 { let tracker = LifetimeTracked(0) func f1() -> Int { return 2 } func f2() -> String { return "b" } } #if _runtime(_ObjC) @objc class WeakUnownedObjCClass: NSObject, WeakUnownedTestsP1, WeakUnownedTestsP2 { let tracker = LifetimeTracked(0) func f1() -> Int { return 2 } func f2() -> String { return "b" } } #endif // The four tests below populate objects with different types // but identical overall structure. // This function is used by all four to verify that the resulting // Mirror objects have the expected entries. func verifyWeakUnownedReflection (_ m: Mirror, expectedClass: ExpectedClass.Type ) { let i = m.children.makeIterator() func verifyClassField(child: (label: String?, value: Any), name: String) { expectEqual(child.label, name) let v = child.value as? ExpectedClass expectNotNil(v) expectEqual(v!.f1(), 2) } func verifyExistentialField(child: (label: String?, value: Any), name: String) { expectEqual(child.label, name) expectNotNil(child.value) let vp1 = child.value as? WeakUnownedTestsP1 expectNotNil(vp1) expectEqual(vp1!.f1(), 2) let vp2 = child.value as? WeakUnownedTestsP2 expectNotNil(vp2) expectEqual(vp2!.f2(), "b") let v = child.value as? ExpectedClass expectNotNil(v) expectEqual(v!.f1(), 2) let m = Mirror(reflecting: v!) expectEqual(m.displayStyle, .`class`) // TODO: Find a way to verify that the existential wrapper carries // the expected protocol witnesses. The current Swift runtime does // a very good job of hiding this from users. } verifyClassField(child: i.next()!, name: "strong_class") verifyExistentialField(child: i.next()!, name: "strong_existential") verifyClassField(child: i.next()!, name: "weak_class") verifyExistentialField(child: i.next()!, name: "weak_existential") verifyClassField(child: i.next()!, name: "unowned_safe_class") verifyExistentialField(child: i.next()!, name: "unowned_safe_existential") verifyClassField(child: i.next()!, name: "unowned_unsafe_class") verifyExistentialField(child: i.next()!, name: "unowned_unsafe_existential") expectNil(i.next()) // The original bug report from https://github.com/apple/swift/issues/47864 // crashed when the print() code attempted to reflect the contents of an // unowned field. // The tests above _should_ suffice to check this, but let's print everything // anyway just to be sure. for c in m.children { print(c.label ?? "?", c.value) } } #if _runtime(_ObjC) // Related: https://github.com/apple/swift/issues/47864 reported a crash when // using 'Mirror' to inspect Swift class objects containing unowned pointers // to Obj-C class objects. mirrors.test("Weak and Unowned Obj-C refs in class") { class SwiftClassWithWeakAndUnowned { var strong_class: WeakUnownedObjCClass var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 weak var weak_class: WeakUnownedObjCClass? weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)? unowned(safe) let unowned_safe_class: WeakUnownedObjCClass unowned(safe) let unowned_safe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 unowned(unsafe) let unowned_unsafe_class: WeakUnownedObjCClass unowned(unsafe) let unowned_unsafe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 init(_ objc: WeakUnownedObjCClass) { self.strong_class = objc self.strong_existential = objc self.weak_class = objc self.weak_existential = objc self.unowned_safe_class = objc self.unowned_safe_existential = objc self.unowned_unsafe_class = objc self.unowned_unsafe_existential = objc } } if #available(SwiftStdlib 5.3, *) { let objc = WeakUnownedObjCClass() let classWithReferences = SwiftClassWithWeakAndUnowned(objc) let m = Mirror(reflecting: classWithReferences) expectEqual(m.displayStyle, .`class`) expectEqual(m.description, "Mirror for SwiftClassWithWeakAndUnowned") expectEqual(m.subjectType, SwiftClassWithWeakAndUnowned.self) verifyWeakUnownedReflection(m, expectedClass: WeakUnownedObjCClass.self) } } mirrors.test("Weak and Unowned Obj-C refs in struct") { struct SwiftStructWithWeakAndUnowned { var strong_class: WeakUnownedObjCClass var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 weak var weak_class: WeakUnownedObjCClass? weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)? unowned(safe) let unowned_safe_class: WeakUnownedObjCClass unowned(safe) let unowned_safe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 unowned(unsafe) let unowned_unsafe_class: WeakUnownedObjCClass unowned(unsafe) let unowned_unsafe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 init(_ objc: WeakUnownedObjCClass) { self.strong_class = objc self.strong_existential = objc self.weak_class = objc self.weak_existential = objc self.unowned_safe_class = objc self.unowned_safe_existential = objc self.unowned_unsafe_class = objc self.unowned_unsafe_existential = objc } } if #available(SwiftStdlib 5.3, *) { let objc = WeakUnownedObjCClass() let structWithReferences = SwiftStructWithWeakAndUnowned(objc) let m = Mirror(reflecting: structWithReferences) expectEqual(m.displayStyle, .`struct`) expectEqual(m.description, "Mirror for SwiftStructWithWeakAndUnowned") expectEqual(m.subjectType, SwiftStructWithWeakAndUnowned.self) verifyWeakUnownedReflection(m, expectedClass: WeakUnownedObjCClass.self) } } #endif mirrors.test("Weak and Unowned Swift refs in class") { class SwiftClassWithWeakAndUnowned { var strong_class: WeakUnownedSwiftClass var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 weak var weak_class: WeakUnownedSwiftClass? weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)? unowned(safe) let unowned_safe_class: WeakUnownedSwiftClass unowned(safe) let unowned_safe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2) unowned(unsafe) let unowned_unsafe_class: WeakUnownedSwiftClass unowned(unsafe) let unowned_unsafe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2) init(_ swift: WeakUnownedSwiftClass) { self.strong_class = swift self.strong_existential = swift self.weak_class = swift self.weak_existential = swift self.unowned_safe_class = swift self.unowned_safe_existential = swift self.unowned_unsafe_class = swift self.unowned_unsafe_existential = swift } } if #available(SwiftStdlib 5.3, *) { let swift = WeakUnownedSwiftClass() let classWithReferences = SwiftClassWithWeakAndUnowned(swift) let m = Mirror(reflecting: classWithReferences) expectEqual(m.displayStyle, .`class`) expectEqual(m.description, "Mirror for SwiftClassWithWeakAndUnowned") expectEqual(m.subjectType, SwiftClassWithWeakAndUnowned.self) verifyWeakUnownedReflection(m, expectedClass: WeakUnownedSwiftClass.self) } } mirrors.test("Weak and Unowned Swift refs in struct") { struct SwiftStructWithWeakAndUnowned { var strong_class: WeakUnownedSwiftClass var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2 weak var weak_class: WeakUnownedSwiftClass? weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)? unowned(safe) let unowned_safe_class: WeakUnownedSwiftClass unowned(safe) let unowned_safe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2) unowned(unsafe) let unowned_unsafe_class: WeakUnownedSwiftClass unowned(unsafe) let unowned_unsafe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2) init(_ swift: WeakUnownedSwiftClass) { self.strong_class = swift self.strong_existential = swift self.weak_class = swift self.weak_existential = swift self.unowned_safe_class = swift self.unowned_safe_existential = swift self.unowned_unsafe_class = swift self.unowned_unsafe_existential = swift } } if #available(SwiftStdlib 5.3, *) { let swift = WeakUnownedSwiftClass() let structWithReferences = SwiftStructWithWeakAndUnowned(swift) let m = Mirror(reflecting: structWithReferences) expectEqual(m.displayStyle, .`struct`) expectEqual(m.description, "Mirror for SwiftStructWithWeakAndUnowned") expectEqual(m.subjectType, SwiftStructWithWeakAndUnowned.self) verifyWeakUnownedReflection(m, expectedClass: WeakUnownedSwiftClass.self) } } //===--- Suppressed Superclass Mirrors ------------------------------------===// mirrors.test("Class/Root/NoSuperclassMirror") { class B : CustomReflectable { var b: String = "two" var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .suppressed) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) expectNil(b.superclassMirror) expectEqual(1, b.children.count) expectEqual("bee", b.children.first!.label) } mirrors.test("class/UncustomizedSuper/NoSuperclassMirror") { class A { var a: Int = 1 } class B : A, CustomReflectable { var b: UInt = 42 var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .suppressed) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) expectNil(b.superclassMirror) } mirrors.test("class/CustomizedSuper/NoSuperclassMirror") { class A : CustomReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror(self, children: ["aye": a]) } } class B : A { var b: UInt = 42 override var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .suppressed) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) expectNil(b.superclassMirror) } //===--- Override Superclass Mirrors --------------------------------------===// mirrors.test("class/CustomizedSuper/SuperclassCustomMirror/Direct") { class A : CustomReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror(self, children: ["aye": a]) } } // B inherits A directly class B : A { var b: UInt = 42 override var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .customized({ super.customMirror })) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) expectEqual("aye", a.children.first!.label) expectNil(a.superclassMirror) } } mirrors.test("class/CustomizedSuper/SuperclassCustomMirror/Indirect") { class A : CustomReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror(self, children: ["aye": a]) } } class X : A {} class Y : X {} // B inherits A indirectly through X and Y class B : Y { var b: UInt = 42 override var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .customized({ super.customMirror })) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let y = expectNotNil(b.superclassMirror) { expectTrue(y.subjectType == Y.self) if let x = expectNotNil(y.superclassMirror) { expectTrue(x.subjectType == X.self) expectEqual(0, x.children.count) if let a = expectNotNil(x.superclassMirror) { expectTrue(a.subjectType == A.self) if let aye = expectNotNil(a.children.first) { expectEqual("aye", aye.label) } } } } } mirrors.test("class/CustomizedSuper/SuperclassCustomMirror/Indirect2") { class A : CustomLeafReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror( self, children: ["aye": a]) } } class X : A {} class Y : X {} // B inherits A indirectly through X and Y class B : Y { var b: UInt = 42 override var customMirror: Mirror { return Mirror( self, children: ["bee": b], ancestorRepresentation: .customized({ super.customMirror })) } } let b = Mirror(reflecting: B()) expectTrue(b.subjectType == B.self) if let a = expectNotNil(b.superclassMirror) { expectTrue(a.subjectType == A.self) if let aye = expectNotNil(a.children.first) { expectEqual("aye", aye.label) } } } mirrors.test("class/Cluster") { class A : CustomLeafReflectable { var a: Int = 1 var customMirror: Mirror { return Mirror( self, children: ["aye": a]) } } class X : A {} class Y : X {} let a = Mirror(reflecting: Y()) expectTrue(a.subjectType == A.self) if let aye = expectNotNil(a.children.first) { expectEqual("aye", aye.label) } } //===--- Miscellaneous ----------------------------------------------------===// //===----------------------------------------------------------------------===// protocol Box { associatedtype Value var value: Value {get} } mirrors.test("Extended Existential (struct)") { struct Container: Box { var value: Value } func genericErase(_ value: T) -> Any { value } let container: any Box = Container(value: 42) if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { let subject = genericErase(container) let mirror = Mirror(reflecting: subject) let children = mirror.children expectEqual(1, children.count) let first = children.first! expectEqual("value", first.label) expectEqual(42, first.value as! Int) } } protocol OBox: AnyObject { associatedtype Value var value: Value {get} } mirrors.test("Extended Existential (class)") { class Container: OBox { var value: Value init(value: Value) { self.value = value } } func genericErase(_ value: T) -> Any { value } let container: any OBox = Container(value: 42) if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { let subject = genericErase(container) let mirror = Mirror(reflecting: subject) let children = mirror.children expectEqual(1, children.count) let first = children.first! expectEqual("value", first.label) expectEqual(42, first.value as! Int) } } mirrors.test("Extended Existential (metatype)") { class Container: Box { var value: Value init(value: Value) { self.value = value } } func genericErase(_ value: T) -> Any { value } let t: any Box.Type = Container.self if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { let subject = genericErase(t) let mirror = Mirror(reflecting: subject) let children = mirror.children expectEqual(0, children.count) } } mirrors.test("Addressing") { let m0 = Mirror(reflecting: [1, 2, 3]) expectEqual(1, m0.descendant(0) as? Int) expectEqual(2, m0.descendant(1) as? Int) expectEqual(3, m0.descendant(2) as? Int) let m1 = Mirror(reflecting: (a: ["one", "two", "three"], 4)) let ott0 = m1.descendant(0) as? [String] expectNotNil(ott0) let ott1 = m1.descendant("a") as? [String] expectNotNil(ott1) if ott0 != nil && ott1 != nil { expectEqualSequence(ott0!, ott1!) } expectEqual(4, m1.descendant(1) as? Int) expectEqual(4, m1.descendant(".1") as? Int) expectEqual("one", m1.descendant(0, 0) as? String) expectEqual("two", m1.descendant(0, 1) as? String) expectEqual("three", m1.descendant(0, 2) as? String) expectEqual("one", m1.descendant("a", 0) as? String) struct Zee : CustomReflectable { var customMirror: Mirror { return Mirror(self, children: ["bark": 1, "bite": 0]) } } let x = [ (a: ["one", "two", "three"], b: Zee()), (a: ["five"], b: Zee()), (a: [], b: Zee())] let m = Mirror(reflecting: x) let two = m.descendant(0, "a", 1) expectEqual("two", two as? String) expectEqual(1, m.descendant(1, 1, "bark") as? Int) expectEqual(0, m.descendant(1, 1, "bite") as? Int) expectNil(m.descendant(1, 1, "bork")) } #if !os(WASI) // Trap tests aren't available on WASI. mirrors.test("Invalid Path Type") .skip(.custom( { _isFastAssertConfiguration() }, reason: "this trap is not guaranteed to happen in -Ounchecked")) .code { struct X : MirrorPath {} let m = Mirror(reflecting: [1, 2, 3]) expectEqual(1, m.descendant(0) as? Int) expectCrashLater() _ = m.descendant(X()) } #endif mirrors.test("PlaygroundQuickLook") { // Customization works. struct CustomQuickie : CustomPlaygroundQuickLookable { var customPlaygroundQuickLook: PlaygroundQuickLook { return .point(1.25, 42) } } switch PlaygroundQuickLook(reflecting: CustomQuickie()) { case .point(1.25, 42): break default: expectTrue(false) } // PlaygroundQuickLook support from Legacy Mirrors works. switch PlaygroundQuickLook(reflecting: true) { case .bool(true): break default: expectTrue(false) } // With no Legacy Mirror QuickLook support, we fall back to // String(reflecting: ). struct X {} switch PlaygroundQuickLook(reflecting: X()) { case .text(let text): #if _runtime(_ObjC) // FIXME: Enable if non-objc hasSuffix is implemented. expectTrue(text.contains(").X"), text) #endif default: expectTrue(false) } struct Y : CustomDebugStringConvertible { var debugDescription: String { return "Why?" } } switch PlaygroundQuickLook(reflecting: Y()) { case .text("Why?"): break default: expectTrue(false) } } class Parent {} extension Parent : _DefaultCustomPlaygroundQuickLookable { var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook { return .text("base") } } class Child : Parent { } class FancyChild : Parent, CustomPlaygroundQuickLookable { var customPlaygroundQuickLook: PlaygroundQuickLook { return .text("child") } } mirrors.test("_DefaultCustomPlaygroundQuickLookable") { // testing the workaround for custom quicklookables in subclasses switch PlaygroundQuickLook(reflecting: Child()) { case .text("base"): break default: expectUnreachable("Base custom quicklookable was expected") } switch PlaygroundQuickLook(reflecting: FancyChild()) { case .text("child"): break default: expectUnreachable("FancyChild custom quicklookable was expected") } } mirrors.test("String.init") { expectEqual("42", String(42)) expectEqual("42", String("42")) expectEqual("42", String(reflecting: 42)) expectEqual("\"42\"", String(reflecting: "42")) } //===--- Structs ----------------------------------------------------------===// //===----------------------------------------------------------------------===// struct StructWithDefaultMirror { let s: String init (_ s: String) { self.s = s } } mirrors.test("Struct/NonGeneric/DefaultMirror") { do { var output = "" dump(StructWithDefaultMirror("123"), to: &output) expectEqual("▿ Mirror.StructWithDefaultMirror\n - s: \"123\"\n", output) } do { // Build a String around an interpolation as a way of smoke-testing that // the internal _Mirror implementation gets memory management right. var output = "" dump(StructWithDefaultMirror("\(456)"), to: &output) expectEqual("▿ Mirror.StructWithDefaultMirror\n - s: \"456\"\n", output) } expectEqual( .`struct`, Mirror(reflecting: StructWithDefaultMirror("")).displayStyle) } struct GenericStructWithDefaultMirror { let first: T let second: U } mirrors.test("Struct/Generic/DefaultMirror") { do { let value = GenericStructWithDefaultMirror( first: 123, second: ["abc", 456, 789.25]) var output = "" dump(value, to: &output) let expected = "▿ Mirror.GenericStructWithDefaultMirror>>\n" + " - first: 123\n" + " ▿ second: 3 elements\n" + " ▿ Optional(\"abc\")\n" + " - some: \"abc\"\n" + " ▿ Optional(456)\n" + " - some: 456\n" + " ▿ Optional(789.25)\n" + " - some: 789.25\n" expectEqual(expected, output) } } //===--- Enums ------------------------------------------------------------===// //===----------------------------------------------------------------------===// enum NoPayloadEnumWithDefaultMirror { case A, ß } mirrors.test("Enum/NoPayload/DefaultMirror") { do { let value: [NoPayloadEnumWithDefaultMirror] = [.A, .ß] var output = "" dump(value, to: &output) let expected = "▿ 2 elements\n" + " - Mirror.NoPayloadEnumWithDefaultMirror.A\n" + " - Mirror.NoPayloadEnumWithDefaultMirror.ß\n" expectEqual(expected, output) } } enum SingletonNonGenericEnumWithDefaultMirror { case OnlyOne(Int) } mirrors.test("Enum/SingletonNonGeneric/DefaultMirror") { do { let value = SingletonNonGenericEnumWithDefaultMirror.OnlyOne(5) var output = "" dump(value, to: &output) let expected = "▿ Mirror.SingletonNonGenericEnumWithDefaultMirror.OnlyOne\n" + " - OnlyOne: 5\n" expectEqual(expected, output) } } enum ZeroSizedEnumWithDefaultMirror { case π } enum SingletonZeroSizedEnumWithDefaultMirror { case wrap(ZeroSizedEnumWithDefaultMirror) } mirrors.test("Enum/SingletonZeroSizedEnumWithDefaultMirror/DefaultMirror") { do { let value = SingletonZeroSizedEnumWithDefaultMirror.wrap(.π) var output = "" dump(value, to: &output) let expected = "▿ Mirror.SingletonZeroSizedEnumWithDefaultMirror.wrap\n" + " - wrap: Mirror.ZeroSizedEnumWithDefaultMirror.π\n" expectEqual(expected, output) } } enum SingletonGenericEnumWithDefaultMirror { case OnlyOne(T) } mirrors.test("Enum/SingletonGeneric/DefaultMirror") { do { let value = SingletonGenericEnumWithDefaultMirror.OnlyOne("IIfx") var output = "" dump(value, to: &output) let expected = "▿ Mirror.SingletonGenericEnumWithDefaultMirror.OnlyOne\n" + " - OnlyOne: \"IIfx\"\n" expectEqual(expected, output) } expectEqual(0, LifetimeTracked.instances) do { let value = SingletonGenericEnumWithDefaultMirror.OnlyOne( LifetimeTracked(0)) expectEqual(1, LifetimeTracked.instances) var output = "" dump(value, to: &output) } expectEqual(0, LifetimeTracked.instances) } enum SinglePayloadNonGenericEnumWithDefaultMirror { case Cat case Dog case Volleyball(String, Int) } mirrors.test("Enum/SinglePayloadNonGeneric/DefaultMirror") { do { let value: [SinglePayloadNonGenericEnumWithDefaultMirror] = [.Cat, .Dog, .Volleyball("Wilson", 2000)] var output = "" dump(value, to: &output) let expected = "▿ 3 elements\n" + " - Mirror.SinglePayloadNonGenericEnumWithDefaultMirror.Cat\n" + " - Mirror.SinglePayloadNonGenericEnumWithDefaultMirror.Dog\n" + " ▿ Mirror.SinglePayloadNonGenericEnumWithDefaultMirror.Volleyball\n" + " ▿ Volleyball: (2 elements)\n" + " - .0: \"Wilson\"\n" + " - .1: 2000\n" expectEqual(expected, output) } } enum SinglePayloadGenericEnumWithDefaultMirror { case Well case Faucet case Pipe(T, U) } mirrors.test("Enum/SinglePayloadGeneric/DefaultMirror") { do { let value: [SinglePayloadGenericEnumWithDefaultMirror] = [.Well, .Faucet, .Pipe(408, [415])] var output = "" dump(value, to: &output) let expected = "▿ 3 elements\n" + " - Mirror.SinglePayloadGenericEnumWithDefaultMirror>.Well\n" + " - Mirror.SinglePayloadGenericEnumWithDefaultMirror>.Faucet\n" + " ▿ Mirror.SinglePayloadGenericEnumWithDefaultMirror>.Pipe\n" + " ▿ Pipe: (2 elements)\n" + " - .0: 408\n" + " ▿ .1: 1 element\n" + " - 415\n" expectEqual(expected, output) } } enum MultiPayloadTagBitsNonGenericEnumWithDefaultMirror { case Plus case SE30 case Classic(mhz: Int) case Performa(model: Int) } mirrors.test("Enum/MultiPayloadTagBitsNonGeneric/DefaultMirror") { do { let value: [MultiPayloadTagBitsNonGenericEnumWithDefaultMirror] = [.Plus, .SE30, .Classic(mhz: 16), .Performa(model: 220)] var output = "" dump(value, to: &output) let expected = "▿ 4 elements\n" + " - Mirror.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Plus\n" + " - Mirror.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.SE30\n" + " ▿ Mirror.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Classic\n" + " ▿ Classic: (1 element)\n" + " - mhz: 16\n" + " ▿ Mirror.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Performa\n" + " ▿ Performa: (1 element)\n" + " - model: 220\n" expectEqual(expected, output) } } class Floppy { let capacity: Int init(capacity: Int) { self.capacity = capacity } } class CDROM { let capacity: Int init(capacity: Int) { self.capacity = capacity } } enum MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror { case MacWrite case MacPaint case FileMaker case ClarisWorks(floppy: Floppy) case HyperCard(cdrom: CDROM) } mirrors.test("Enum/MultiPayloadSpareBitsNonGeneric/DefaultMirror") { do { let value: [MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror] = [.MacWrite, .MacPaint, .FileMaker, .ClarisWorks(floppy: Floppy(capacity: 800)), .HyperCard(cdrom: CDROM(capacity: 600))] var output = "" dump(value, to: &output) let expected = "▿ 5 elements\n" + " - Mirror.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacWrite\n" + " - Mirror.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacPaint\n" + " - Mirror.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.FileMaker\n" + " ▿ Mirror.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.ClarisWorks\n" + " ▿ ClarisWorks: (1 element)\n" + " ▿ floppy: Mirror.Floppy #0\n" + " - capacity: 800\n" + " ▿ Mirror.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.HyperCard\n" + " ▿ HyperCard: (1 element)\n" + " ▿ cdrom: Mirror.CDROM #1\n" + " - capacity: 600\n" expectEqual(expected, output) } } enum MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror { case MacWrite case MacPaint case FileMaker case ClarisWorks(floppy: Bool) case HyperCard(cdrom: Bool) } mirrors.test("Enum/MultiPayloadTagBitsSmallNonGeneric/DefaultMirror") { do { let value: [MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror] = [.MacWrite, .MacPaint, .FileMaker, .ClarisWorks(floppy: true), .HyperCard(cdrom: false)] var output = "" dump(value, to: &output) let expected = "▿ 5 elements\n" + " - Mirror.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacWrite\n" + " - Mirror.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacPaint\n" + " - Mirror.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.FileMaker\n" + " ▿ Mirror.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.ClarisWorks\n" + " ▿ ClarisWorks: (1 element)\n" + " - floppy: true\n" + " ▿ Mirror.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.HyperCard\n" + " ▿ HyperCard: (1 element)\n" + " - cdrom: false\n" expectEqual(expected, output) } } enum MultiPayloadGenericEnumWithDefaultMirror { case IIe case IIgs case Centris(ram: T) case Quadra(hdd: U) case PowerBook170 case PowerBookDuo220 } mirrors.test("Enum/MultiPayloadGeneric/DefaultMirror") { do { let value: [MultiPayloadGenericEnumWithDefaultMirror] = [.IIe, .IIgs, .Centris(ram: 4096), .Quadra(hdd: "160MB"), .PowerBook170, .PowerBookDuo220] var output = "" dump(value, to: &output) let expected = "▿ 6 elements\n" + " - Mirror.MultiPayloadGenericEnumWithDefaultMirror.IIe\n" + " - Mirror.MultiPayloadGenericEnumWithDefaultMirror.IIgs\n" + " ▿ Mirror.MultiPayloadGenericEnumWithDefaultMirror.Centris\n" + " ▿ Centris: (1 element)\n" + " - ram: 4096\n" + " ▿ Mirror.MultiPayloadGenericEnumWithDefaultMirror.Quadra\n" + " ▿ Quadra: (1 element)\n" + " - hdd: \"160MB\"\n" + " - Mirror.MultiPayloadGenericEnumWithDefaultMirror.PowerBook170\n" + " - Mirror.MultiPayloadGenericEnumWithDefaultMirror.PowerBookDuo220\n" expectEqual(expected, output) } expectEqual(0, LifetimeTracked.instances) do { let value = MultiPayloadGenericEnumWithDefaultMirror .Quadra(hdd: LifetimeTracked(0)) expectEqual(1, LifetimeTracked.instances) var output = "" dump(value, to: &output) } expectEqual(0, LifetimeTracked.instances) } enum Foo { indirect case Foo(Int) case Bar(T) } enum List { case Nil indirect case Cons(first: T, rest: List) } mirrors.test("Enum/IndirectGeneric/DefaultMirror") { let x = Foo.Foo(22) let y = Foo.Bar("twenty-two") expectEqual("\(x)", "Foo(22)") expectEqual("\(y)", "Bar(\"twenty-two\")") let list = List.Cons(first: 0, rest: .Cons(first: 1, rest: .Nil)) expectEqual("Cons(first: 0, rest: Mirror.List.Cons(first: 1, rest: Mirror.List.Nil))", "\(list)") } enum MyError: Error { case myFirstError(LifetimeTracked) } mirrors.test("Enum/CaseName/Error") { // Just make sure this doesn't leak. let e: Error = MyError.myFirstError(LifetimeTracked(0)) _ = String(describing: e) } class Brilliant : CustomReflectable { let first: Int let second: String init(_ fst: Int, _ snd: String) { self.first = fst self.second = snd } var customMirror: Mirror { return Mirror(self, children: ["first": first, "second": second, "self": self]) } } //===--- Custom mirrors ---------------------------------------------------===// //===----------------------------------------------------------------------===// /// Subclasses inherit their parents' custom mirrors. class Irradiant : Brilliant { init() { super.init(400, "") } } mirrors.test("CustomMirror") { do { var output = "" dump(Brilliant(123, "four five six"), to: &output) let expected = "▿ Mirror.Brilliant #0\n" + " - first: 123\n" + " - second: \"four five six\"\n" + " ▿ self: Mirror.Brilliant #0\n" expectEqual(expected, output) } do { var output = "" dump(Brilliant(123, "four five six"), to: &output, maxDepth: 0) expectEqual("▹ Mirror.Brilliant #0\n", output) } do { var output = "" dump(Brilliant(123, "four five six"), to: &output, maxItems: 3) let expected = "▿ Mirror.Brilliant #0\n" + " - first: 123\n" + " - second: \"four five six\"\n" + " (1 more child)\n" expectEqual(expected, output) } do { var output = "" dump(Brilliant(123, "four five six"), to: &output, maxItems: 2) let expected = "▿ Mirror.Brilliant #0\n" + " - first: 123\n" + " (2 more children)\n" expectEqual(expected, output) } do { var output = "" dump(Brilliant(123, "four five six"), to: &output, maxItems: 1) let expected = "▿ Mirror.Brilliant #0\n" + " (3 children)\n" expectEqual(expected, output) } } mirrors.test("CustomMirrorIsInherited") { do { var output = "" dump(Irradiant(), to: &output) let expected = "▿ Mirror.Brilliant #0\n" + " - first: 400\n" + " - second: \"\"\n" + " ▿ self: Mirror.Brilliant #0\n" expectEqual(expected, output) } } //===--- Metatypes --------------------------------------------------------===// //===----------------------------------------------------------------------===// protocol SomeNativeProto {} protocol SomeOtherNativeProto {} extension Int: SomeNativeProto {} class SomeClass {} mirrors.test("MetatypeMirror") { do { var output = "" let concreteMetatype = Int.self dump(concreteMetatype, to: &output) let expectedInt = "- Swift.Int #0\n" expectEqual(expectedInt, output) let anyMetatype: Any.Type = Int.self output = "" dump(anyMetatype, to: &output) expectEqual(expectedInt, output) let nativeProtocolMetatype: SomeNativeProto.Type = Int.self output = "" dump(nativeProtocolMetatype, to: &output) expectEqual(expectedInt, output) let concreteClassMetatype = SomeClass.self let expectedSomeClass = "- Mirror.SomeClass #0\n" output = "" dump(concreteClassMetatype, to: &output) expectEqual(expectedSomeClass, output) let nativeProtocolConcreteMetatype = SomeNativeProto.self let expectedNativeProtocolConcrete = "- Mirror.SomeNativeProto #0\n" output = "" dump(nativeProtocolConcreteMetatype, to: &output) expectEqual(expectedNativeProtocolConcrete, output) let nativeProtocolCompositionMetatype = (SomeNativeProto & SomeOtherNativeProto).self output = "" dump(nativeProtocolCompositionMetatype, to: &output) expectEqual( "- Mirror.SomeNativeProto & Mirror.SomeOtherNativeProto #0\n", output) } } class MetatypeExampleClass {} class MetatypeExampleSubclass: MetatypeExampleClass {} final class MetatypeExampleFinalClass {} enum MetatypeExampleEnum {} struct MetatypeContainer { var before = 42 var before2 = 43 var structType = String.self var enumType = MetatypeExampleEnum.self var tupleType = (Int, String, AnyObject).self var functionType = (() -> Void).self var classType = MetatypeExampleClass.self var subclassType: MetatypeExampleClass.Type = MetatypeExampleSubclass.self var finalClassType = MetatypeExampleFinalClass.self var existentialType: (any Any).Type = Any.self var existentialType2: Any.Type = Any.self var after = 45 } mirrors.test("MetatypeFields") { var output = "" let container = MetatypeContainer() dump(container, to: &output) expectEqual(""" ▿ Mirror.MetatypeContainer - before: 42 - before2: 43 - structType: Swift.String #0 - enumType: Mirror.MetatypeExampleEnum #1 - tupleType: (Swift.Int, Swift.String, Swift.AnyObject) #2 - functionType: () -> () #3 - classType: Mirror.MetatypeExampleClass #4 - subclassType: Mirror.MetatypeExampleSubclass #5 - finalClassType: Mirror.MetatypeExampleFinalClass #6 - existentialType: Any #7 - existentialType2: Any #7 - after: 45 """, output) } //===--- Tuples -----------------------------------------------------------===// //===----------------------------------------------------------------------===// mirrors.test("TupleMirror") { do { var output = "" let tuple = (Brilliant(384, "seven six eight"), StructWithDefaultMirror("nine")) dump(tuple, to: &output) let expected = "▿ (2 elements)\n" + " ▿ .0: Mirror.Brilliant #0\n" + " - first: 384\n" + " - second: \"seven six eight\"\n" + " ▿ self: Mirror.Brilliant #0\n" + " ▿ .1: Mirror.StructWithDefaultMirror\n" + " - s: \"nine\"\n" expectEqual(expected, output) expectEqual(.tuple, Mirror(reflecting: tuple).displayStyle) } do { // A tuple of stdlib types with mirrors. var output = "" let tuple = (1, 2.5, false, "three") dump(tuple, to: &output) let expected = "▿ (4 elements)\n" + " - .0: 1\n" + " - .1: 2.5\n" + " - .2: false\n" + " - .3: \"three\"\n" expectEqual(expected, output) } do { // A nested tuple. var output = "" let tuple = (1, ("Hello", "World")) dump(tuple, to: &output) let expected = "▿ (2 elements)\n" + " - .0: 1\n" + " ▿ .1: (2 elements)\n" + " - .0: \"Hello\"\n" + " - .1: \"World\"\n" expectEqual(expected, output) } } //===--- Standard library types -------------------------------------------===// //===----------------------------------------------------------------------===// mirrors.test("String/Mirror") { do { var output = "" dump("", to: &output) let expected = "- \"\"\n" expectEqual(expected, output) } do { // U+0061 LATIN SMALL LETTER A // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK // U+1F425 FRONT-FACING BABY CHICK var output = "" dump("\u{61}\u{304b}\u{3099}\u{1f425}", to: &output) let expected = "- \"\u{61}\u{304b}\u{3099}\u{1f425}\"\n" expectEqual(expected, output) } } mirrors.test("String.UTF8View/Mirror") { // U+0061 LATIN SMALL LETTER A // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK var output = "" dump("\u{61}\u{304b}\u{3099}".utf8, to: &output) let expected = "▿ UTF8View(\"\u{61}\u{304b}\u{3099}\")\n" + " - 97\n" + " - 227\n" + " - 129\n" + " - 139\n" + " - 227\n" + " - 130\n" + " - 153\n" expectEqual(expected, output) } mirrors.test("String.UTF16View/Mirror") { // U+0061 LATIN SMALL LETTER A // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK // U+1F425 FRONT-FACING BABY CHICK var output = "" dump("\u{61}\u{304b}\u{3099}\u{1f425}".utf16, to: &output) let expected = "▿ StringUTF16(\"\u{61}\u{304b}\u{3099}\u{1f425}\")\n" + " - 97\n" + " - 12363\n" + " - 12441\n" + " - 55357\n" + " - 56357\n" expectEqual(expected, output) } mirrors.test("String.UnicodeScalarView/Mirror") { // U+0061 LATIN SMALL LETTER A // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK // U+1F425 FRONT-FACING BABY CHICK var output = "" dump("\u{61}\u{304b}\u{3099}\u{1f425}".unicodeScalars, to: &output) let expected = "▿ StringUnicodeScalarView(\"\u{61}\u{304b}\u{3099}\u{1f425}\")\n" + " - \"\u{61}\"\n" + " - \"\\u{304B}\"\n" + " - \"\\u{3099}\"\n" + " - \"\\u{0001F425}\"\n" expectEqual(expected, output) } mirrors.test("Character/Mirror") { do { // U+0061 LATIN SMALL LETTER A let input: Character = "\u{61}" var output = "" dump(input, to: &output) let expected = "- \"\u{61}\"\n" expectEqual(expected, output) } do { // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK let input: Character = "\u{304b}\u{3099}" var output = "" dump(input, to: &output) let expected = "- \"\u{304b}\u{3099}\"\n" expectEqual(expected, output) } do { // U+1F425 FRONT-FACING BABY CHICK let input: Character = "\u{1f425}" var output = "" dump(input, to: &output) let expected = "- \"\u{1f425}\"\n" expectEqual(expected, output) } } mirrors.test("UnicodeScalar") { do { // U+0061 LATIN SMALL LETTER A let input: UnicodeScalar = "\u{61}" var output = "" dump(input, to: &output) let expected = "- \"\u{61}\"\n" expectEqual(expected, output) } do { // U+304B HIRAGANA LETTER KA let input: UnicodeScalar = "\u{304b}" var output = "" dump(input, to: &output) let expected = "- \"\\u{304B}\"\n" expectEqual(expected, output) } do { // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK let input: UnicodeScalar = "\u{3099}" var output = "" dump(input, to: &output) let expected = "- \"\\u{3099}\"\n" expectEqual(expected, output) } do { // U+1F425 FRONT-FACING BABY CHICK let input: UnicodeScalar = "\u{1f425}" var output = "" dump(input, to: &output) let expected = "- \"\\u{0001F425}\"\n" expectEqual(expected, output) } } mirrors.test("Bool") { do { var output = "" dump(false, to: &output) let expected = "- false\n" expectEqual(expected, output) } do { var output = "" dump(true, to: &output) let expected = "- true\n" expectEqual(expected, output) } } // FIXME: these tests should cover Float80. // FIXME: these tests should be automatically generated from the list of // available floating point types. mirrors.test("Float") { do { var output = "" dump(Float.nan, to: &output) let expected = "- nan\n" expectEqual(expected, output) } do { var output = "" dump(Float.infinity, to: &output) let expected = "- inf\n" expectEqual(expected, output) } do { let input: Float = 42.125 var output = "" dump(input, to: &output) let expected = "- 42.125\n" expectEqual(expected, output) } } mirrors.test("Double") { do { var output = "" dump(Double.nan, to: &output) let expected = "- nan\n" expectEqual(expected, output) } do { var output = "" dump(Double.infinity, to: &output) let expected = "- inf\n" expectEqual(expected, output) } do { let input: Double = 42.125 var output = "" dump(input, to: &output) let expected = "- 42.125\n" expectEqual(expected, output) } } mirrors.test("StaticString/Mirror") { do { var output = "" dump("" as StaticString, to: &output) let expected = "- \"\"\n" expectEqual(expected, output) } do { // U+0061 LATIN SMALL LETTER A // U+304B HIRAGANA LETTER KA // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK // U+1F425 FRONT-FACING BABY CHICK var output = "" dump("\u{61}\u{304b}\u{3099}\u{1f425}" as StaticString, to: &output) let expected = "- \"\u{61}\u{304b}\u{3099}\u{1f425}\"\n" expectEqual(expected, output) } } mirrors.test("DictionaryIterator/Mirror") { let d: [MinimalHashableValue : OpaqueValue] = [ MinimalHashableValue(0) : OpaqueValue(0) ] var output = "" dump(d.makeIterator(), to: &output) let expected = "- Swift.Dictionary>.Iterator\n" expectEqual(expected, output) } mirrors.test("SetIterator/Mirror") { let s: Set = [ MinimalHashableValue(0)] var output = "" dump(s.makeIterator(), to: &output) let expected = "- Swift.Set.Iterator\n" expectEqual(expected, output) } //===--- Regressions ------------------------------------------------------===// //===----------------------------------------------------------------------===// // A struct type and class type whose NominalTypeDescriptor.FieldNames // data is exactly eight bytes long. FieldNames data of exactly // 4 or 8 or 16 bytes was once miscompiled on arm64. struct EightByteFieldNamesStruct { let abcdef = 42 } class EightByteFieldNamesClass { let abcdef = 42 } mirrors.test("FieldNamesBug") { do { let expected = "▿ Mirror.EightByteFieldNamesStruct\n" + " - abcdef: 42\n" var output = "" dump(EightByteFieldNamesStruct(), to: &output) expectEqual(expected, output) } do { let expected = "▿ Mirror.EightByteFieldNamesClass #0\n" + " - abcdef: 42\n" var output = "" dump(EightByteFieldNamesClass(), to: &output) expectEqual(expected, output) } } mirrors.test("MirrorMirror") { let object = 1 let mirror = Mirror(reflecting: object) let mirrorMirror = Mirror(reflecting: mirror) expectEqual(0, mirrorMirror.children.count) } mirrors.test("OpaquePointer/null") { // Don't crash on null pointers. rdar://problem/19708338 let pointer: OpaquePointer? = nil let mirror = Mirror(reflecting: pointer as Any) expectEqual(0, mirror.children.count) } struct a { enum c{} } class d {} struct e { var constraints: [Int: a.c] = [:] } mirrors.test("GenericNestedTypeField") { let x = e() expectTrue(type(of: Mirror(reflecting: x).children.first!.value) == [Int: a.c].self) } extension OtherOuter { struct Inner {} } extension OtherOuterGeneric { struct Inner {} } mirrors.test("SymbolicReferenceInsideType") { let s = OtherStruct(a: OtherOuter.Inner(), b: OtherOuterGeneric.Inner()) var output = "" dump(s, to: &output) let expected = "▿ Mirror.OtherStruct\n" + " - a: Mirror.OtherOuter.Inner\n" + " - b: Mirror.OtherOuterGeneric.Inner\n" expectEqual(expected, output) } protocol P1 { } protocol P2 { } protocol P3 { } struct ConformsToP1: P1 { } struct ConformsToP2: P2 { } struct ConformsToP3: P3 { } struct OuterTwoParams {} struct ConformsToP1AndP2 : P1, P2 { } extension OuterTwoParams where U == T { struct InnerEqualParams { var x: T var y: U var z: V } } mirrors.test("GenericNestedWithSameTypeConstraints") { let value = OuterTwoParams.InnerEqualParams(x: ConformsToP1AndP2(), y: ConformsToP1AndP2(), z: ConformsToP3()) var output = "" dump(value, to: &output) let expected = "▿ (extension in Mirror):Mirror.OuterTwoParams.InnerEqualParams\n" + " - x: Mirror.ConformsToP1AndP2\n" + " - y: Mirror.ConformsToP1AndP2\n" + " - z: Mirror.ConformsToP3\n" expectEqual(expected, output) } @_alignment(16) struct CustomAlignment { var x: Int var y: Int } mirrors.test("CustomAlignment") { let value = CustomAlignment(x: 123, y: 321) var output = "" dump(value, to: &output) let expected = "▿ Mirror.CustomAlignment\n" + " - x: 123\n" + " - y: 321\n" expectEqual(expected, output) } protocol STSTagProtocol {} struct STSOuter : STSTagProtocol {} enum STSContainer { class Superclass {} class Subclass: Superclass where T == STSOuter { class ExtraNested: Superclass {} } class GenericSuperclass {} class Subclass2: GenericSuperclass where T == STSOuter {} class Subclass3: Superclass where T == U.Element {} class MoreNesting { class Subclass: Superclass where T == STSOuter {} } struct Fields where T == STSOuter { var x: T? var y: U? } enum Cases where T == STSOuter { case a(T) case b(U) } } // A new type with an easily-recognizable, easily-strippable suffix character. enum STSContainer℠ { class Superclass {} class GenericSuperclass {} } extension STSContainer℠ where T == STSOuter { class Subclass: Superclass { class ExtraNested: Superclass {} } class Subclass2: GenericSuperclass {} class MoreNesting { class Subclass: Superclass {} } struct Fields { var x: T? var y: U? } enum Cases { case a(T) case b(U) } } var sameTypeSuite = TestSuite("Mirrors.SameTypeConstraints") func testSTSDump( _ regular: RegularValue, _ ext: ExtensionValue, _ expected: String ) { var output = "" dump(regular, to: &output) expectEqual(expected, output) func clean(_ dumpOutput: String) -> String { // This isn't efficient but it doesn't have to be. var result = dumpOutput result.removeAll { $0 == "℠" } if let openParenIndex = result.firstIndex(of: "(") { if result[openParenIndex...].hasPrefix("(extension in Mirror):") { let colonIndex = result[openParenIndex...].firstIndex(of: ":")! result.removeSubrange(openParenIndex...colonIndex) } } return result } var extensionOutput = "" dump(ext, to: &extensionOutput) expectEqual(expected, clean(extensionOutput)) } func testSTSDump(_ regular: RegularValue, _ expected: String) { var output = "" dump(regular, to: &output) expectEqual(expected, output) } if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { sameTypeSuite.test("Subclass") { testSTSDump(STSContainer.Subclass(), STSContainer℠.Subclass(), """ - Mirror.STSContainer.Subclass #0 - super: Mirror.STSContainer.Superclass\n """) testSTSDump(STSContainer.Subclass2(), STSContainer℠.Subclass2(), """ - Mirror.STSContainer.Subclass2 #0 - super: Mirror.STSContainer.GenericSuperclass\n """) testSTSDump(STSContainer.Subclass3<[STSOuter]>(), """ - Mirror.STSContainer.Subclass3> #0 - super: Mirror.STSContainer.Superclass\n """) testSTSDump(STSContainer.Subclass.ExtraNested(), STSContainer℠.Subclass.ExtraNested(), """ - Mirror.STSContainer.Subclass.ExtraNested #0 - super: Mirror.STSContainer.Superclass\n """) testSTSDump(STSContainer.MoreNesting.Subclass(), STSContainer℠.MoreNesting.Subclass(), """ - Mirror.STSContainer.MoreNesting.Subclass #0 - super: Mirror.STSContainer.Superclass\n """) } sameTypeSuite.test("Fields") { testSTSDump(STSContainer.Fields(), STSContainer℠.Fields(), """ ▿ Mirror.STSContainer.Fields - x: nil - y: nil\n """) } sameTypeSuite.test("Cases") { testSTSDump(STSContainer.Cases.a(.init()), STSContainer℠.Cases.a(.init()), """ ▿ Mirror.STSContainer.Cases.a - a: Mirror.STSOuter\n """) testSTSDump(STSContainer.Cases.b(.init()), STSContainer℠.Cases.b(.init()), """ ▿ Mirror.STSContainer.Cases.b - b: 0\n """) } } runAllTests()