Skip to content

Commit 91f0a33

Browse files
authored
Merge pull request #38 from benlangmuir/testloc-unicode
[test] Split TestLocation column into explicit utf8/utf16 indices
2 parents 8fb0f95 + 49b7684 commit 91f0a33

File tree

4 files changed

+69
-34
lines changed

4 files changed

+69
-34
lines changed

β€ŽSources/ISDBTestSupport/TestLocation.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,23 @@ public struct TestLocation: Hashable {
2222
/// The one-based line number.
2323
public var line: Int
2424

25-
/// The one-based column number.
26-
///
27-
/// FIXME: define utf8 vs. utf16 column index.
28-
public var column: Int
25+
/// The one-based UTF-8 column index.
26+
public var utf8Column: Int
2927

30-
public init(url: URL, line: Int, column: Int) {
28+
/// The one-based UTF-16 column index.
29+
public var utf16Column: Int
30+
31+
public init(url: URL, line: Int, utf8Column: Int, utf16Column: Int) {
3132
self.url = url
3233
self.line = line
33-
self.column = column
34+
self.utf8Column = utf8Column
35+
self.utf16Column = utf16Column
3436
}
3537
}
3638

3739
extension TestLocation: Comparable {
3840
public static func <(a: TestLocation, b: TestLocation) -> Bool {
39-
return (a.url.path, a.line, a.column) < (b.url.path, b.line, b.column)
41+
return (a.url.path, a.line, a.utf8Column) < (b.url.path, b.line, b.utf8Column)
4042
}
4143
}
4244

@@ -48,7 +50,7 @@ extension SymbolLocation {
4850
path: loc.url.path,
4951
isSystem: isSystem,
5052
line: loc.line,
51-
utf8Column: loc.column)
53+
utf8Column: loc.utf8Column)
5254
}
5355
}
5456

@@ -61,5 +63,5 @@ extension Symbol {
6163
}
6264

6365
extension TestLocation: CustomStringConvertible {
64-
public var description: String { "\(url.path):\(line):\(column)" }
66+
public var description: String { "\(url.path):\(line):\(utf8Column)" }
6567
}

β€ŽSources/ISDBTestSupport/TestLocationScanner.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public struct TestLocationScanner {
7575
var state = State.normal(prev: "_")
7676
var i = str.startIndex
7777
var line = 1
78-
var column = 1
78+
var lineStart = i
7979

8080
while i != str.endIndex {
8181
let c = str[i]
@@ -87,39 +87,47 @@ public struct TestLocationScanner {
8787
state = .normal(prev: c)
8888

8989
case (.comment(let start, "*"), "/"):
90-
let name: String
91-
let col: Int
90+
let nameStart: String.Index
91+
let locIndex: String.Index
9292
if str[start] == "<" {
93-
// Location of the leading '/'.
94-
name = String(str[str.index(after: start)..<str.index(before: i)])
95-
col = column - str.distance(from: start, to: i) - 2
93+
nameStart = str.index(after: start)
94+
locIndex = str.index(start, offsetBy: -2) // subtract '/' and '*'
9695
} else {
97-
// Location after the trailing '/'.
98-
name = String(str[start..<str.index(before: i)])
99-
col = column + 1
96+
nameStart = start
97+
locIndex = str.index(after: i) // after trailing '/'
10098
}
10199

102-
let loc = TestLocation(url: url, line: line, column: col)
100+
let name = String(str[nameStart..<str.index(before: i)])
101+
102+
let loc = TestLocation(
103+
url: url,
104+
line: line,
105+
utf8Column: 1 + str.utf8.distance(from: lineStart, to: locIndex),
106+
utf16Column: 1 + str.utf16.distance(from: lineStart, to: locIndex))
107+
103108
if let prevLoc = result.updateValue(loc, forKey: name) {
104109
throw Error.duplicateKey(name, prevLoc, loc)
105110
}
111+
106112
state = .normal(prev: "_")
107113

108114
case (.comment(_, "/"), "*"):
109-
throw Error.nestedComment(TestLocation(url: url, line: line, column: column))
115+
throw Error.nestedComment(TestLocation(
116+
url: url,
117+
line: line,
118+
utf8Column: 1 + str.utf8.distance(from: lineStart, to: i),
119+
utf16Column: 1 + str.utf16.distance(from: lineStart, to: i)))
110120

111121
case (.comment(let start, _), _):
112122
state = .comment(bodyStart: start, prev: c)
113123
}
114124

125+
i = str.index(after: i)
126+
115127
if c == "\n" {
116128
line += 1
117-
column = 1
118-
} else {
119-
column += 1
129+
lineStart = i
120130
}
121-
122-
i = str.index(after: i)
123131
}
124132
}
125133

β€ŽTests/IndexStoreDBTests/LocationScannerTests.swift

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,37 @@ final class LocationScannerTests: XCTestCase {
2222
var url: URL
2323
var name: String
2424
var line: Int
25-
var column: Int
26-
init(url: URL = LocationScannerTests.magicURL, _ name: String, _ line: Int, _ column: Int) {
25+
var utf8Column: Int
26+
var utf16Column: Int
27+
28+
init(
29+
url: URL = LocationScannerTests.magicURL,
30+
_ name: String,
31+
_ line: Int,
32+
utf8Column: Int,
33+
utf16Column: Int)
34+
{
2735
self.url = url
2836
self.name = name
2937
self.line = line
30-
self.column = column
38+
self.utf8Column = utf8Column
39+
self.utf16Column = utf16Column
40+
}
41+
42+
init(url: URL = LocationScannerTests.magicURL, _ name: String, _ line: Int, _ column: Int) {
43+
self.init(url: url, name, line, utf8Column: column, utf16Column: column)
3144
}
45+
3246
init(_ name: String, _ loc: TestLocation) {
33-
self.url = loc.url
34-
self.name = name
35-
self.line = loc.line
36-
self.column = loc.column
47+
self.init(
48+
url: loc.url,
49+
name, loc.line,
50+
utf8Column: loc.utf8Column,
51+
utf16Column: loc.utf16Column)
3752
}
3853
static func <(a: Loc, b: Loc) -> Bool {
39-
return (a.url.absoluteString, a.line, a.column, a.name) <
40-
(b.url.absoluteString, b.line, b.column, b.name)
54+
return (a.url.absoluteString, a.line, a.utf8Column, a.name) <
55+
(b.url.absoluteString, b.line, b.utf8Column, b.name)
4156
}
4257
}
4358

@@ -153,4 +168,13 @@ final class LocationScannerTests: XCTestCase {
153168
Loc(url: proj1.appendingPathComponent("rec/c.swift", isDirectory: false), "c", 1, 11),
154169
])
155170
}
171+
172+
func testUnicode() throws {
173+
XCTAssertEqual(try scanString("πŸ˜ƒ/*a*/"), [Loc("a", 1, utf8Column: 10, utf16Column: 8)])
174+
XCTAssertEqual(try scanString("πŸ˜ƒ/*<a*/"), [Loc("a", 1, utf8Column: 5, utf16Column: 3)])
175+
XCTAssertEqual(try scanString("Δ†/*a*/"), [Loc("a", 1, utf8Column: 8, utf16Column: 7)])
176+
XCTAssertEqual(try scanString("Δ†/*<a*/"), [Loc("a", 1, utf8Column: 3, utf16Column: 2)])
177+
XCTAssertEqual(try scanString("πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§/*a*/"), [Loc("a", 1, utf8Column: 31, utf16Column: 17)])
178+
XCTAssertEqual(try scanString("πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§/*<a*/"), [Loc("a", 1, utf8Column: 26, utf16Column: 12)])
179+
}
156180
}

β€ŽTests/IndexStoreDBTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extension LocationScannerTests {
3535
("testName", testName),
3636
("testNested", testNested),
3737
("testSmall", testSmall),
38+
("testUnicode", testUnicode),
3839
]
3940
}
4041

0 commit comments

Comments
Β (0)