Skip to content

Commit 5811a04

Browse files
lilyballmillenomi
authored andcommitted
Add some tests for KeyPath issues
Test to make sure the `String -> KeyPath` table used for the `NSKeyValueObservingCustomization` callbacks isn't screwed up by observing another object's property with the same name from within the callbacks. Test `NSSortDescriptor.keyPath` to ensure it's also not screwed up by creating sort descriptors for the same property on different objects.
1 parent fafaa33 commit 5811a04

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

Diff for: test/stdlib/KVOKeyPaths.swift

+61
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,68 @@ print("target removed")
105105
// CHECK-NEXT: swiftValue 42, objcValue three
106106
// CHECK-NEXT: swiftValue 42, objcValue four
107107
// CHECK-NEXT: swiftValue 13, objcValue four
108+
// The next 2 logs are actually a bug and shouldn't happen
108109
// CHECK-NEXT: swiftValue 13, objcValue four
109110
// CHECK-NEXT: swiftValue 13, objcValue four
110111
// CHECK-NEXT: target removed
111112

113+
//===----------------------------------------------------------------------===//
114+
// Test NSKeyValueObservingCustomization issue with observing from the callbacks
115+
//===----------------------------------------------------------------------===//
116+
117+
class Target2 : NSObject, NSKeyValueObservingCustomization {
118+
dynamic var name: String?
119+
120+
class Dummy : NSObject {
121+
dynamic var name: String?
122+
}
123+
124+
// In both of the callbacks, observe another property with the same key path.
125+
// We do it in both because we're not sure which callback is invoked first.
126+
// This ensures that using KVO with key paths from one callback doesn't interfere
127+
// with the ability to look up the key path using the other.
128+
static func keyPathsAffectingValue(for key: AnyKeyPath) -> Set<AnyKeyPath> {
129+
print("keyPathsAffectingValue: key == \\.name:", key == \Target2.name)
130+
_ = Dummy().observe(\.name) { (_, _) in }
131+
return []
132+
}
133+
134+
static func automaticallyNotifiesObservers(for key: AnyKeyPath) -> Bool {
135+
print("automaticallyNotifiesObservers: key == \\.name:", key == \Target2.name)
136+
_ = Dummy().observe(\.name) { (_, _) in }
137+
return true
138+
}
139+
}
140+
141+
print("registering observer for Target2")
142+
withExtendedLifetime(Target2()) { (target) in
143+
_ = target.observe(\.name) { (_, _) in }
144+
}
145+
print("observer removed")
146+
147+
// CHECK-LABEL: registering observer for Target2
148+
// CHECK-DAG: keyPathsAffectingValue: key == \.name: true
149+
// CHECK-DAG: automaticallyNotifiesObservers: key == \.name: true
150+
// CHECK-NEXT: observer removed
151+
152+
//===----------------------------------------------------------------------===//
153+
// Test NSSortDescriptor keyPath support
154+
//===----------------------------------------------------------------------===//
155+
156+
// This one doesn't really match the context of "KVO KeyPaths" but it's close enough
157+
158+
class Sortable1 : NSObject {
159+
@objc var name: String?
160+
}
161+
162+
class Sortable2 : NSObject {
163+
@objc var name: String?
164+
}
165+
166+
print("creating NSSortDescriptor")
167+
let descriptor = NSSortDescriptor(keyPath: \Sortable1.name, ascending: true)
168+
_ = NSSortDescriptor(keyPath: \Sortable2.name, ascending: true)
169+
print("keyPath == \\Sortable1.name:", descriptor.keyPath == \Sortable1.name)
170+
171+
// CHECK-LABEL: creating NSSortDescriptor
172+
// CHECK-NEXT: keyPath == \Sortable1.name: true

0 commit comments

Comments
 (0)