Skip to content

Commit 3857357

Browse files
klundbergphausler
authored andcommitted
Add block/boolean NSPredicates, NSCompoundPredicate, and NSArray predicate method
1 parent 93cd136 commit 3857357

File tree

6 files changed

+270
-24
lines changed

6 files changed

+270
-24
lines changed

Foundation.xcodeproj/project.pbxproj

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@
254254
61E011811C1B5998000037DD /* CFMessagePort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5D88DC1BBC9AEC00234F36 /* CFMessagePort.c */; };
255255
61E011821C1B599A000037DD /* CFMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5D88D01BBC9AAC00234F36 /* CFMachPort.c */; };
256256
AE35A1861CBAC85E0042DB84 /* SwiftFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
257+
7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */; };
258+
7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */; };
257259
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */ = {isa = PBXBuildFile; fileRef = CE19A88B1C23AA2300B4CB6A /* NSStringTestData.txt */; };
258260
D31302011C30CEA900295652 /* NSConcreteValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31302001C30CEA900295652 /* NSConcreteValue.swift */; };
259261
D370696E1C394FBF00295652 /* NSKeyedUnarchiver-RangeTest.plist in Resources */ = {isa = PBXBuildFile; fileRef = D370696D1C394FBF00295652 /* NSKeyedUnarchiver-RangeTest.plist */; };
@@ -547,15 +549,15 @@
547549
5B5D89A51BBDC06800234F36 /* CFStringEncodingDatabase.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFStringEncodingDatabase.c; sourceTree = "<group>"; };
548550
5B5D89A71BBDC09700234F36 /* CFStringScanner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFStringScanner.c; sourceTree = "<group>"; };
549551
5B5D89A91BBDC11100234F36 /* CFLocaleKeys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFLocaleKeys.c; sourceTree = "<group>"; };
552+
5B6228BA1C179041009587FE /* CFRunArray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFRunArray.c; sourceTree = "<group>"; };
553+
5B6228BC1C179049009587FE /* CFRunArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFRunArray.h; sourceTree = "<group>"; };
554+
5B6228BE1C179052009587FE /* CFAttributedString.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFAttributedString.c; sourceTree = "<group>"; };
555+
5B6228C01C17905B009587FE /* CFAttributedString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFAttributedString.h; sourceTree = "<group>"; };
550556
5B6F17921C48631C00935030 /* TestNSNull.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNull.swift; sourceTree = "<group>"; };
551557
5B6F17931C48631C00935030 /* TestNSNumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNumberFormatter.swift; sourceTree = "<group>"; };
552558
5B6F17941C48631C00935030 /* TestNSTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSTask.swift; sourceTree = "<group>"; };
553559
5B6F17951C48631C00935030 /* TestNSXMLDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSXMLDocument.swift; sourceTree = "<group>"; };
554560
5B6F17961C48631C00935030 /* TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
555-
5B6228BA1C179041009587FE /* CFRunArray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFRunArray.c; sourceTree = "<group>"; };
556-
5B6228BC1C179049009587FE /* CFRunArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFRunArray.h; sourceTree = "<group>"; };
557-
5B6228BE1C179052009587FE /* CFAttributedString.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFAttributedString.c; sourceTree = "<group>"; };
558-
5B6228C01C17905B009587FE /* CFAttributedString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFAttributedString.h; sourceTree = "<group>"; };
559561
5B7C8A6E1BEA7F8F00C5B690 /* libCoreFoundation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCoreFoundation.a; sourceTree = BUILT_PRODUCTS_DIR; };
560562
5B94E8811C430DE70055C035 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
561563
5BC1D8BC1BF3ADFE009D3973 /* TestNSCharacterSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSCharacterSet.swift; sourceTree = "<group>"; };
@@ -610,6 +612,8 @@
610612
61E0117B1C1B554D000037DD /* TestNSRunLoop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSRunLoop.swift; sourceTree = "<group>"; };
611613
61F8AE7C1C180FC600FB62F0 /* TestNSNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNotificationCenter.swift; sourceTree = "<group>"; };
612614
6E203B8C1C1303BB003B2576 /* TestNSBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSBundle.swift; sourceTree = "<group>"; };
615+
790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSCompoundPredicate.swift; sourceTree = "<group>"; };
616+
7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSPredicate.swift; sourceTree = "<group>"; };
613617
7A7D6FBA1C16439400957E2E /* TestNSURLResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSURLResponse.swift; sourceTree = "<group>"; };
614618
83712C8D1C1684900049AD49 /* TestNSURLRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSURLRequest.swift; sourceTree = "<group>"; };
615619
844DC3321C17584F005611F9 /* TestNSScanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSScanner.swift; sourceTree = "<group>"; };
@@ -1159,10 +1163,13 @@
11591163
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */,
11601164
EA66F63C1BF1619600136161 /* TestNSArray.swift */,
11611165
6E203B8C1C1303BB003B2576 /* TestNSBundle.swift */,
1166+
A5A34B551C18C85D00FD972B /* TestNSByteCountFormatter.swift */,
11621167
52829AD61C160D64003BC4EF /* TestNSCalendar.swift */,
11631168
5BC1D8BC1BF3ADFE009D3973 /* TestNSCharacterSet.swift */,
1169+
790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */,
11641170
DCDBB8321C1768AC00313299 /* TestNSData.swift */,
11651171
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */,
1172+
2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */,
11661173
EA66F63D1BF1619600136161 /* TestNSDictionary.swift */,
11671174
525AECEB1BF2C96400D15BB0 /* TestNSFileManager.swift */,
11681175
88D28DE61C13AE9000494606 /* TestNSGeometry.swift */,
@@ -1180,6 +1187,7 @@
11801187
5B6F17931C48631C00935030 /* TestNSNumberFormatter.swift */,
11811188
D834F9931C31C4060023812A /* TestNSOrderedSet.swift */,
11821189
4DC1D07F1C12EEEF00B5948A /* TestNSPipe.swift */,
1190+
7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */,
11831191
400E22641C1A4E58007C5933 /* TestNSProcessInfo.swift */,
11841192
EA66F6401BF1619600136161 /* TestNSPropertyList.swift */,
11851193
E876A73D1C1180E000F279EC /* TestNSRange.swift */,
@@ -1195,15 +1203,13 @@
11951203
EA66F6431BF1619600136161 /* TestNSURL.swift */,
11961204
83712C8D1C1684900049AD49 /* TestNSURLRequest.swift */,
11971205
7A7D6FBA1C16439400957E2E /* TestNSURLResponse.swift */,
1206+
555683BC1C1250E70041D4C6 /* TestNSUserDefaults.swift */,
11981207
C2A9D75B1C15C08B00993803 /* TestNSUUID.swift */,
1208+
D3047AEB1C38BC3300295652 /* TestNSValue.swift */,
11991209
5B6F17951C48631C00935030 /* TestNSXMLDocument.swift */,
12001210
5B40F9F11C125187000E72E3 /* TestNSXMLParser.swift */,
1201-
555683BC1C1250E70041D4C6 /* TestNSUserDefaults.swift */,
12021211
5B6F17961C48631C00935030 /* TestUtils.swift */,
1203-
A5A34B551C18C85D00FD972B /* TestNSByteCountFormatter.swift */,
1204-
D3047AEB1C38BC3300295652 /* TestNSValue.swift */,
12051212
E19E17DB1C2225930023AF4D /* TestNSXMLDocument.swift */,
1206-
2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */,
12071213
);
12081214
name = Tests;
12091215
sourceTree = "<group>";
@@ -1952,6 +1958,7 @@
19521958
5B13B33E1C582D4C00651CE2 /* TestNSProcessInfo.swift in Sources */,
19531959
5B13B33F1C582D4C00651CE2 /* TestNSPropertyList.swift in Sources */,
19541960
5B13B32C1C582D4C00651CE2 /* TestNSDate.swift in Sources */,
1961+
7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */,
19551962
5B13B33B1C582D4C00651CE2 /* TestNSNumberFormatter.swift in Sources */,
19561963
5B13B3301C582D4C00651CE2 /* TestNSHTTPCookie.swift in Sources */,
19571964
5B13B3361C582D4C00651CE2 /* TestNSLocale.swift in Sources */,
@@ -1984,6 +1991,7 @@
19841991
5B13B3271C582D4C00651CE2 /* TestNSArray.swift in Sources */,
19851992
5B13B3461C582D4C00651CE2 /* TestNSTask.swift in Sources */,
19861993
555683BD1C1250E70041D4C6 /* TestNSUserDefaults.swift in Sources */,
1994+
7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */,
19871995
);
19881996
runOnlyForDeploymentPostprocessing = 0;
19891997
};

Foundation/NSCompoundPredicate.swift

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,43 @@ public enum NSCompoundPredicateType : UInt {
1919

2020
public class NSCompoundPredicate : NSPredicate {
2121

22-
public init(type: NSCompoundPredicateType, subpredicates: [NSPredicate]) { NSUnimplemented() }
22+
public init(type: NSCompoundPredicateType, subpredicates: [NSPredicate]) {
23+
if type == .NotPredicateType && subpredicates.count == 0 {
24+
preconditionFailure("Unsupported predicate count of \(subpredicates.count) for \(type)")
25+
}
26+
self.compoundPredicateType = type
27+
self.subpredicates = subpredicates
28+
super.init(value: false)
29+
}
2330
public required init?(coder: NSCoder) { NSUnimplemented() }
2431

25-
public var compoundPredicateType: NSCompoundPredicateType { NSUnimplemented() }
26-
public var subpredicates: [AnyObject] { NSUnimplemented() }
27-
32+
public let compoundPredicateType: NSCompoundPredicateType
33+
public let subpredicates: [NSPredicate]
34+
2835
/*** Convenience Methods ***/
29-
public init(andPredicateWithSubpredicates subpredicates: [NSPredicate]) { NSUnimplemented() }
30-
public init(orPredicateWithSubpredicates subpredicates: [NSPredicate]) { NSUnimplemented() }
31-
public init(notPredicateWithSubpredicate predicate: NSPredicate) { NSUnimplemented() }
36+
public convenience init(andPredicateWithSubpredicates subpredicates: [NSPredicate]) {
37+
self.init(type: .AndPredicateType, subpredicates: subpredicates)
38+
}
39+
public convenience init(orPredicateWithSubpredicates subpredicates: [NSPredicate]) {
40+
self.init(type: .OrPredicateType, subpredicates: subpredicates)
41+
}
42+
public convenience init(notPredicateWithSubpredicate predicate: NSPredicate) {
43+
self.init(type: .NotPredicateType, subpredicates: [predicate])
44+
}
45+
46+
override public func evaluateWithObject(_ object: AnyObject?, substitutionVariables bindings: [String : AnyObject]?) -> Bool {
47+
switch compoundPredicateType {
48+
case .AndPredicateType:
49+
return subpredicates.reduce(true, combine: {
50+
$0 && $1.evaluateWithObject(object, substitutionVariables: bindings)
51+
})
52+
case .OrPredicateType:
53+
return subpredicates.reduce(false, combine: {
54+
$0 || $1.evaluateWithObject(object, substitutionVariables: bindings)
55+
})
56+
case .NotPredicateType:
57+
// safe to get the 0th item here since we trap if there's not at least one on init
58+
return !(subpredicates[0].evaluateWithObject(object, substitutionVariables: bindings))
59+
}
60+
}
3261
}

Foundation/NSPredicate.swift

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@
1111
// Predicates wrap some combination of expressions and operators and when evaluated return a BOOL.
1212

1313
public class NSPredicate : NSObject, NSSecureCoding, NSCopying {
14-
14+
15+
private enum PredicateKind {
16+
case Boolean(Bool)
17+
case Block((AnyObject?, [String : AnyObject]?) -> Bool)
18+
// TODO: case for init(format:argumentArray:)
19+
// TODO: case for init(fromMetadataQueryString:)
20+
}
21+
22+
private let kind: PredicateKind
23+
1524
public static func supportsSecureCoding() -> Bool {
1625
return true
1726
}
@@ -37,23 +46,46 @@ public class NSPredicate : NSObject, NSSecureCoding, NSCopying {
3746

3847
public init?(fromMetadataQueryString queryString: String) { NSUnimplemented() }
3948

40-
public init(value: Bool) { NSUnimplemented() } // return predicates that always evaluate to true/false
41-
42-
public init(block: (AnyObject, [String : AnyObject]?) -> Bool) { NSUnimplemented() }
49+
public init(value: Bool) {
50+
kind = .Boolean(value)
51+
super.init()
52+
} // return predicates that always evaluate to true/false
53+
54+
public init(block: (AnyObject?, [String : AnyObject]?) -> Bool) {
55+
kind = .Block(block)
56+
super.init()
57+
}
4358

4459
public var predicateFormat: String { NSUnimplemented() } // returns the format string of the predicate
4560

4661
public func predicateWithSubstitutionVariables(_ variables: [String : AnyObject]) -> Self { NSUnimplemented() } // substitute constant values for variables
4762

48-
public func evaluateWithObject(_ object: AnyObject?) -> Bool { NSUnimplemented() } // evaluate a predicate against a single object
63+
public func evaluateWithObject(_ object: AnyObject?) -> Bool {
64+
return evaluateWithObject(object, substitutionVariables: nil)
65+
} // evaluate a predicate against a single object
4966

50-
public func evaluateWithObject(_ object: AnyObject?, substitutionVariables bindings: [String : AnyObject]?) -> Bool { NSUnimplemented() } // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered
67+
public func evaluateWithObject(_ object: AnyObject?, substitutionVariables bindings: [String : AnyObject]?) -> Bool {
68+
if bindings != nil {
69+
NSUnimplemented()
70+
}
71+
72+
switch kind {
73+
case let .Boolean(value):
74+
return value
75+
case let .Block(block):
76+
return block(object, bindings)
77+
}
78+
} // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered
5179

5280
public func allowEvaluation() { NSUnimplemented() } // Force a predicate which was securely decoded to allow evaluation
5381
}
5482

5583
extension NSArray {
56-
public func filteredArrayUsingPredicate(_ predicate: NSPredicate) -> [AnyObject] { NSUnimplemented() } // evaluate a predicate against an array of objects and return a filtered array
84+
public func filteredArrayUsingPredicate(_ predicate: NSPredicate) -> [AnyObject] {
85+
return bridge().filter({ object in
86+
return predicate.evaluateWithObject(object)
87+
})
88+
} // evaluate a predicate against an array of objects and return a filtered array
5789
}
5890

5991
extension NSMutableArray {
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See http://swift.org/LICENSE.txt for license information
7+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+
//
9+
10+
#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
11+
import Foundation
12+
import XCTest
13+
#else
14+
import SwiftFoundation
15+
import SwiftXCTest
16+
#endif
17+
18+
class TestNSCompoundPredicate: XCTestCase {
19+
20+
static var allTests: [(String, TestNSCompoundPredicate -> () throws -> Void)] {
21+
return [
22+
("test_NotPredicate", test_NotPredicate),
23+
("test_AndPredicateWithNoSubpredicates", test_AndPredicateWithNoSubpredicates),
24+
("test_AndPredicateWithOneSubpredicate", test_AndPredicateWithOneSubpredicate),
25+
("test_AndPredicateWithMultipleSubpredicates", test_AndPredicateWithMultipleSubpredicates),
26+
("test_OrPredicateWithNoSubpredicates", test_OrPredicateWithNoSubpredicates),
27+
("test_OrPredicateWithOneSubpredicate", test_OrPredicateWithOneSubpredicate),
28+
("test_OrPredicateWithMultipleSubpredicates", test_OrPredicateWithMultipleSubpredicates),
29+
("test_OrPredicateShortCircuits", test_OrPredicateShortCircuits),
30+
("test_AndPredicateShortCircuits", test_AndPredicateShortCircuits),
31+
]
32+
}
33+
34+
private func eval(_ predicate: NSPredicate, object: NSObject = NSObject()) -> Bool {
35+
return predicate.evaluateWithObject(object, substitutionVariables: nil)
36+
}
37+
38+
func test_NotPredicate() {
39+
let notTruePredicate = NSCompoundPredicate(notPredicateWithSubpredicate: NSPredicate(value: true))
40+
let notFalsePredicate = NSCompoundPredicate(notPredicateWithSubpredicate: NSPredicate(value: false))
41+
42+
XCTAssertFalse(eval(notTruePredicate))
43+
XCTAssertTrue(eval(notFalsePredicate))
44+
}
45+
46+
func test_AndPredicateWithNoSubpredicates() {
47+
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [])
48+
49+
XCTAssertTrue(eval(predicate))
50+
}
51+
52+
func test_AndPredicateWithOneSubpredicate() {
53+
let truePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(value: true)])
54+
let falsePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(value: false)])
55+
56+
XCTAssertTrue(eval(truePredicate))
57+
XCTAssertFalse(eval(falsePredicate))
58+
}
59+
60+
func test_AndPredicateWithMultipleSubpredicates() {
61+
let truePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(value: true), NSPredicate(value: true)])
62+
let falsePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(value: true), NSPredicate(value: false)])
63+
64+
XCTAssertTrue(eval(truePredicate))
65+
XCTAssertFalse(eval(falsePredicate))
66+
}
67+
68+
69+
func test_OrPredicateWithNoSubpredicates() {
70+
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [])
71+
72+
XCTAssertFalse(eval(predicate))
73+
}
74+
75+
func test_OrPredicateWithOneSubpredicate() {
76+
let truePredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [NSPredicate(value: true)])
77+
let falsePredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [NSPredicate(value: false)])
78+
79+
XCTAssertTrue(eval(truePredicate))
80+
XCTAssertFalse(eval(falsePredicate))
81+
}
82+
83+
func test_OrPredicateWithMultipleSubpredicates() {
84+
let truePredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [NSPredicate(value: true), NSPredicate(value: false)])
85+
let falsePredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [NSPredicate(value: false), NSPredicate(value: false)])
86+
87+
XCTAssertTrue(eval(truePredicate))
88+
XCTAssertFalse(eval(falsePredicate))
89+
}
90+
91+
func test_AndPredicateShortCircuits() {
92+
var shortCircuited = true
93+
94+
let bOK = NSPredicate(value: false)
95+
let bDontEval = NSPredicate(block: { _ in
96+
shortCircuited = false
97+
return true
98+
})
99+
100+
let both = NSCompoundPredicate(andPredicateWithSubpredicates: [bOK, bDontEval])
101+
XCTAssertFalse(eval(both))
102+
XCTAssertTrue(shortCircuited)
103+
}
104+
105+
func test_OrPredicateShortCircuits() {
106+
var shortCircuited = true
107+
108+
let bOK = NSPredicate(value: true)
109+
let bDontEval = NSPredicate(block: { _ in
110+
shortCircuited = false
111+
return true
112+
})
113+
114+
let both = NSCompoundPredicate(orPredicateWithSubpredicates: [bOK, bDontEval])
115+
XCTAssertTrue(eval(both))
116+
XCTAssertTrue(shortCircuited)
117+
}
118+
}

0 commit comments

Comments
 (0)