Skip to content

Commit 5894e8a

Browse files
authored
Merge pull request #1894 from ApolloZhu/fix-nsrange-init-from-range-in-string
NSRange: fix init from region RangeExpression in target String
2 parents 3c41fb2 + cf12a0d commit 5894e8a

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

Foundation/NSRange.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,7 @@ extension NSRange {
260260
public init<R: RangeExpression, S: StringProtocol>(_ region: R, in target: S)
261261
where R.Bound == S.Index {
262262
let r = region.relative(to: target)
263-
self = NSRange(
264-
location: r.lowerBound.encodedOffset - target.startIndex.encodedOffset,
265-
length: r.upperBound.encodedOffset - r.lowerBound.encodedOffset
266-
)
263+
self.init(target._toUTF16Offsets(r))
267264
}
268265

269266
@available(swift, deprecated: 4, renamed: "Range.init(_:)")

TestFoundation/TestNSRange.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class TestNSRange : XCTestCase {
1919
("test_NSUnionRange", test_NSUnionRange),
2020
("test_NSIntersectionRange", test_NSIntersectionRange),
2121
("test_NSStringFromRange", test_NSStringFromRange),
22+
("test_init_region_in_ascii_string", test_init_region_in_ascii_string),
23+
("test_init_region_in_unicode_string", test_init_region_in_unicode_string),
2224
]
2325
}
2426

@@ -126,4 +128,53 @@ class TestNSRange : XCTestCase {
126128
XCTAssertEqual(NSStringFromRange(range), string)
127129
}
128130
}
131+
132+
/// Specialized for the below tests.
133+
private func _assertNSRangeInit<S: StringProtocol, R: RangeExpression>(
134+
_ region: R, in target: S, is rangeString: String
135+
) where R.Bound == S.Index {
136+
XCTAssert(NSEqualRanges(NSRangeFromString(rangeString), NSRange(region, in: target)))
137+
}
138+
139+
func test_init_region_in_ascii_string() {
140+
// all count = 18
141+
let normalString = "1;DROP TABLE users"
142+
143+
_assertNSRangeInit(normalString.index(normalString.startIndex, offsetBy: 2)..<normalString.index(normalString.endIndex, offsetBy: -6), in: normalString, is: "{2, 10}")
144+
_assertNSRangeInit(normalString.index(after: normalString.startIndex)...normalString.index(before: normalString.endIndex), in: normalString, is: "{1, 17}")
145+
_assertNSRangeInit(normalString.startIndex..., in: normalString, is: "{0, 18}")
146+
_assertNSRangeInit(...normalString.firstIndex(of: " ")!, in: normalString, is: "{0, 7}")
147+
_assertNSRangeInit(..<normalString.lastIndex(of: " ")!, in: normalString, is: "{0, 12}")
148+
149+
let normalSubstring: Substring = normalString.split(separator: ";")[1]
150+
151+
_assertNSRangeInit(normalSubstring.range(of: "TABLE")!, in: normalSubstring, is: "{5, 5}")
152+
_assertNSRangeInit(normalSubstring.index(after: normalSubstring.firstIndex(of: " ")!)..<normalSubstring.lastIndex(of: " ")!, in: normalString, is: "{7, 5}")
153+
_assertNSRangeInit(normalSubstring.firstIndex(of: "u")!...normalSubstring.lastIndex(of: "u")!, in: normalSubstring, is: "{11, 1}")
154+
_assertNSRangeInit(normalSubstring.startIndex..., in: normalSubstring, is: "{0, 16}")
155+
_assertNSRangeInit(normalSubstring.startIndex..., in: normalString, is: "{2, 16}")
156+
_assertNSRangeInit(...normalSubstring.lastIndex(of: " ")!, in: normalSubstring, is: "{0, 11}")
157+
_assertNSRangeInit(..<normalSubstring.lastIndex(of: " ")!, in: normalString, is: "{0, 12}")
158+
}
159+
160+
func test_init_region_in_unicode_string() {
161+
// count: 46, utf8: 90, utf16: 54
162+
let unicodeString = "This  is a #naughty👻 string (╯°□°)╯︵ ┻━┻👨‍👩‍👧‍👦)"
163+
164+
_assertNSRangeInit(unicodeString.index(unicodeString.startIndex, offsetBy: 10)..<unicodeString.index(unicodeString.startIndex, offsetBy: 28), in: unicodeString, is: "{10, 19}")
165+
_assertNSRangeInit(unicodeString.index(after: unicodeString.startIndex)...unicodeString.index(before: unicodeString.endIndex), in: unicodeString, is: "{1, 53}")
166+
_assertNSRangeInit(unicodeString.startIndex..., in: unicodeString, is: "{0, 54}")
167+
_assertNSRangeInit(...unicodeString.firstIndex(of: "👻")!, in: unicodeString, is: "{0, 22}")
168+
_assertNSRangeInit(..<unicodeString.range(of: "👨‍👩‍👧‍👦")!.lowerBound, in: unicodeString, is: "{0, 42}")
169+
170+
let unicodeSubstring: Substring = unicodeString[unicodeString.firstIndex(of: "👻")!...]
171+
172+
_assertNSRangeInit(unicodeSubstring.range(of: "👨‍👩‍👧‍👦")!, in: unicodeSubstring, is: "{22, 11}")
173+
_assertNSRangeInit(unicodeSubstring.range(of: "👨")!.lowerBound..<unicodeSubstring.range(of: "👦")!.upperBound, in: unicodeString, is: "{42, 11}")
174+
_assertNSRangeInit(unicodeSubstring.index(after: unicodeSubstring.startIndex)...unicodeSubstring.index(before: unicodeSubstring.endIndex), in: unicodeSubstring, is: "{2, 32}")
175+
_assertNSRangeInit(unicodeSubstring.startIndex..., in: unicodeSubstring, is: "{0, 34}")
176+
_assertNSRangeInit(unicodeSubstring.startIndex..., in: unicodeString, is: "{20, 34}")
177+
_assertNSRangeInit(...unicodeSubstring.firstIndex(of: "")!, in: unicodeSubstring, is: "{0, 12}")
178+
_assertNSRangeInit(..<unicodeSubstring.firstIndex(of: "")!, in: unicodeString, is: "{0, 31}")
179+
}
129180
}

0 commit comments

Comments
 (0)