WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit ada7456

Browse files
committed
Swap ranges upper and lower
1 parent b0d9eb4 commit ada7456

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

Sources/FoundationEssentials/Predicate/NSPredicateConversion.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,11 @@ extension PredicateExpressions.RangeExpressionContains : ConvertibleExpression {
374374
} else if let rangeValue = (range as? _RangeValue)?._anyRange {
375375
// Otherwise, if the range is a captured value then convert it to appropriate comparison expressions based on the range type
376376
switch rangeValue {
377-
case let .range(upper, lower):
377+
case let .range(lower, upper):
378378
let lowerBoundCondition = _comparison(elementExpr, try _expressionForBound(lower), type: .greaterThanOrEqualTo)
379379
let upperBoundCondition = _comparison(elementExpr, try _expressionForBound(upper), type: .lessThan)
380380
return .predicate(NSCompoundPredicate(andPredicateWithSubpredicates: [lowerBoundCondition, upperBoundCondition]))
381-
case let .closed(upper, lower):
381+
case let .closed(lower, upper):
382382
let lowerValue = try _expressionCompatibleValue(for: lower)
383383
let upperValue = try _expressionCompatibleValue(for: upper)
384384
return .predicate(NSComparisonPredicate(

Tests/FoundationEssentialsTests/PredicateConversionTests.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,37 @@ private struct NSPredicateConversionTests {
177177
#expect(!converted.evaluate(with: ObjCObject()))
178178
}
179179

180+
@Test func rangesDistinctBounds() throws {
181+
// Test that captured ranges have correct bounds order in NSPredicate conversion
182+
// This tests the _RangeValue branch in RangeExpressionContains.convert
183+
let lowerDate = Date(timeIntervalSinceReferenceDate: 100)
184+
let upperDate = Date(timeIntervalSinceReferenceDate: 200)
185+
let range = lowerDate ..< upperDate
186+
187+
let predicate = #Predicate<ObjCObject> {
188+
range.contains($0.i)
189+
}
190+
let converted = try #require(convert(predicate))
191+
192+
// Verify the bounds are in the correct order (lower, upper)
193+
#expect(converted == NSPredicate(format: "i >= %@ AND i < %@", lowerDate as NSDate, upperDate as NSDate))
194+
195+
// Create an object with a date in the range
196+
let objInRange = ObjCObject()
197+
objInRange.i = Date(timeIntervalSinceReferenceDate: 150)
198+
#expect(converted.evaluate(with: objInRange), "Date in range should match")
199+
200+
// Create an object with a date outside the range
201+
let objOutOfRange = ObjCObject()
202+
objOutOfRange.i = Date(timeIntervalSinceReferenceDate: 250)
203+
#expect(!converted.evaluate(with: objOutOfRange), "Date outside range should not match")
204+
205+
// Verify that if bounds were swapped, the predicate would be wrong
206+
// (This would be i >= upperDate AND i < lowerDate, which is always false)
207+
let wrongPredicate = NSPredicate(format: "i >= %@ AND i < %@", upperDate as NSDate, lowerDate as NSDate)
208+
#expect(!wrongPredicate.evaluate(with: objInRange), "Swapped bounds would incorrectly reject valid date")
209+
}
210+
180211
@Test func nonObjC() throws {
181212
let predicate = #Predicate<ObjCObject> {
182213
$0.nonObjCKeypath == 2

0 commit comments

Comments
 (0)