mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
225 lines
7.9 KiB
Swift
225 lines
7.9 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SKLogging
|
|
import SKTestSupport
|
|
import SKUtilities
|
|
import SwiftExtensions
|
|
import TSCBasic
|
|
import XCTest
|
|
|
|
fileprivate extension LineTable {
|
|
var lines: [Substring] {
|
|
(0..<lineCount).map { line(at: $0)! }
|
|
}
|
|
}
|
|
|
|
final class LineTableTests: SourceKitLSPTestCase {
|
|
func checkLines(_ string: String, _ expected: [String], file: StaticString = #filePath, line: UInt = #line) {
|
|
let table = LineTable(string)
|
|
XCTAssertEqual(table.lines.map(String.init), expected, file: file, line: line)
|
|
}
|
|
|
|
func checkOffsets(_ string: String, _ expected: [Int], file: StaticString = #filePath, line: UInt = #line) {
|
|
let table = LineTable(string)
|
|
XCTAssertEqual(
|
|
table.lines.map { string.utf8.distance(from: string.startIndex, to: $0.startIndex) },
|
|
expected,
|
|
file: file,
|
|
line: line
|
|
)
|
|
}
|
|
|
|
func testLineTable() {
|
|
checkLines("", [""])
|
|
checkLines("a", ["a"])
|
|
checkLines("abc", ["abc"])
|
|
checkLines("abc\n", ["abc\n", ""])
|
|
checkLines("\n", ["\n", ""])
|
|
checkLines("\n\n", ["\n", "\n", ""])
|
|
checkLines("\r\n", ["\r\n", ""])
|
|
checkLines("\r\r", ["\r", "\r", ""])
|
|
checkLines("a\nb", ["a\n", "b"])
|
|
checkLines("a\nb\n", ["a\n", "b\n", ""])
|
|
checkLines("a\nb\nccccc", ["a\n", "b\n", "ccccc"])
|
|
|
|
checkLines("\u{1}\nb", ["\u{1}\n", "b"])
|
|
checkLines("\u{10000}\nb", ["\u{10000}\n", "b"])
|
|
checkLines("\n\u{10000}", ["\n", "\u{10000}"])
|
|
checkLines("\n\u{10000}b", ["\n", "\u{10000}b"])
|
|
checkLines("\n\u{10000}\nc", ["\n", "\u{10000}\n", "c"])
|
|
checkLines("\n\u{10000}b\nc", ["\n", "\u{10000}b\n", "c"])
|
|
|
|
checkOffsets("a", [0])
|
|
checkOffsets("abc", [0])
|
|
checkOffsets("\n", [0, 1])
|
|
checkOffsets("\n\n", [0, 1, 2])
|
|
checkOffsets("\n\r\n\n", [0, 1, 3, 4])
|
|
checkOffsets("a\nb", [0, 2])
|
|
checkOffsets("a\nb\n", [0, 2, 4])
|
|
checkOffsets("a\nbbb\nccccc", [0, 2, 6])
|
|
checkOffsets("a\nbbb\nccccc", [0, 2, 6])
|
|
|
|
checkOffsets("\u{1}\nb", [0, 2])
|
|
checkOffsets("\u{100}\nb", [0, 3])
|
|
checkOffsets("\u{1000}\nb", [0, 4])
|
|
checkOffsets("\u{10000}\nb", [0, 5])
|
|
checkOffsets("\n\u{10000}", [0, 1])
|
|
checkOffsets("\n\u{10000}b", [0, 1])
|
|
checkOffsets("\n\u{10000}b\nc", [0, 1, 7])
|
|
|
|
XCTAssertEqual(LineTable("").line(at: 0), "")
|
|
XCTAssertEqual(LineTable("\n").line(at: 1), "")
|
|
}
|
|
|
|
func checkLineAndColumns(
|
|
_ table: LineTable,
|
|
_ utf8Offset: Int,
|
|
_ expected: (line: Int, utf16Column: Int),
|
|
file: StaticString = #filePath,
|
|
line: UInt = #line
|
|
) {
|
|
let actual = table.lineAndUTF16ColumnOf(utf8Offset: utf8Offset)
|
|
XCTAssert(actual == expected, "\(actual) != \(expected)", file: file, line: line)
|
|
}
|
|
|
|
func checkUTF8OffsetOf(
|
|
_ table: LineTable,
|
|
_ query: (line: Int, utf16Column: Int),
|
|
_ expected: Int,
|
|
file: StaticString = #filePath,
|
|
line: UInt = #line
|
|
) {
|
|
XCTAssertEqual(
|
|
table.utf8OffsetOf(line: query.line, utf16Column: query.utf16Column),
|
|
expected,
|
|
file: file,
|
|
line: line
|
|
)
|
|
}
|
|
|
|
func checkUTF16ColumnAt(
|
|
_ table: LineTable,
|
|
_ query: (line: Int, utf8Column: Int),
|
|
_ expected: Int,
|
|
file: StaticString = #filePath,
|
|
line: UInt = #line
|
|
) {
|
|
XCTAssertEqual(
|
|
table.utf16ColumnAt(line: query.line, utf8Column: query.utf8Column),
|
|
expected,
|
|
file: file,
|
|
line: line
|
|
)
|
|
}
|
|
|
|
func testLineTableLinePositionTranslation() {
|
|
let t1 = LineTable(
|
|
"""
|
|
0123
|
|
5678
|
|
abcd
|
|
"""
|
|
)
|
|
checkLineAndColumns(t1, 0, (line: 0, utf16Column: 0))
|
|
checkLineAndColumns(t1, 2, (line: 0, utf16Column: 2))
|
|
checkLineAndColumns(t1, 4, (line: 0, utf16Column: 4))
|
|
checkLineAndColumns(t1, 5, (line: 1, utf16Column: 0))
|
|
checkLineAndColumns(t1, 9, (line: 1, utf16Column: 4))
|
|
checkLineAndColumns(t1, 10, (line: 2, utf16Column: 0))
|
|
checkLineAndColumns(t1, 14, (line: 2, utf16Column: 4))
|
|
checkLineAndColumns(t1, 15, (line: 2, utf16Column: 4))
|
|
|
|
checkUTF8OffsetOf(t1, (line: 0, utf16Column: 0), 0)
|
|
checkUTF8OffsetOf(t1, (line: 0, utf16Column: 2), 2)
|
|
checkUTF8OffsetOf(t1, (line: 0, utf16Column: 4), 4)
|
|
checkUTF8OffsetOf(t1, (line: 0, utf16Column: 5), 5)
|
|
checkUTF8OffsetOf(t1, (line: 0, utf16Column: 6), 5) // Recovers to end of line 0
|
|
checkUTF8OffsetOf(t1, (line: 1, utf16Column: 0), 5)
|
|
checkUTF8OffsetOf(t1, (line: 1, utf16Column: 4), 9)
|
|
checkUTF8OffsetOf(t1, (line: 2, utf16Column: 0), 10)
|
|
checkUTF8OffsetOf(t1, (line: 2, utf16Column: 4), 14)
|
|
checkUTF8OffsetOf(t1, (line: 2, utf16Column: 5), 14) // Recovers to end of line 2
|
|
checkUTF8OffsetOf(t1, (line: 3, utf16Column: 0), 14) // Recovers to end of source file
|
|
|
|
checkUTF16ColumnAt(t1, (line: 0, utf8Column: 4), 4)
|
|
checkUTF16ColumnAt(t1, (line: 0, utf8Column: 5), 5)
|
|
checkUTF16ColumnAt(t1, (line: 0, utf8Column: 6), 5) // Recovers to end of line 0
|
|
checkUTF16ColumnAt(t1, (line: 2, utf8Column: 0), 0)
|
|
checkUTF16ColumnAt(t1, (line: 3, utf8Column: 0), 0) // Line out of bounds, so keeps column
|
|
|
|
let t2 = LineTable(
|
|
"""
|
|
こんにちは
|
|
안녕하세요
|
|
\u{1F600}\u{1F648}
|
|
"""
|
|
)
|
|
checkLineAndColumns(t2, 0, (line: 0, utf16Column: 0))
|
|
checkLineAndColumns(t2, 15, (line: 0, utf16Column: 5))
|
|
checkLineAndColumns(t2, 19, (line: 1, utf16Column: 1))
|
|
checkLineAndColumns(t2, 32, (line: 2, utf16Column: 0))
|
|
checkLineAndColumns(t2, 36, (line: 2, utf16Column: 2))
|
|
checkLineAndColumns(t2, 40, (line: 2, utf16Column: 4))
|
|
|
|
checkUTF8OffsetOf(t2, (line: 0, utf16Column: 0), 0)
|
|
checkUTF8OffsetOf(t2, (line: 0, utf16Column: 5), 15)
|
|
checkUTF8OffsetOf(t2, (line: 0, utf16Column: 6), 16)
|
|
checkUTF8OffsetOf(t2, (line: 1, utf16Column: 1), 19)
|
|
checkUTF8OffsetOf(t2, (line: 1, utf16Column: 6), 32)
|
|
checkUTF8OffsetOf(t2, (line: 1, utf16Column: 7), 32) // Recovers to end of line 1
|
|
checkUTF8OffsetOf(t2, (line: 2, utf16Column: 0), 32)
|
|
checkUTF8OffsetOf(t2, (line: 2, utf16Column: 2), 36)
|
|
checkUTF8OffsetOf(t2, (line: 2, utf16Column: 4), 40)
|
|
checkUTF8OffsetOf(t2, (line: 2, utf16Column: 5), 40) // Recovers to end of line 2
|
|
|
|
checkUTF16ColumnAt(t2, (line: 0, utf8Column: 3), 1)
|
|
checkUTF16ColumnAt(t2, (line: 0, utf8Column: 15), 5)
|
|
checkUTF16ColumnAt(t2, (line: 2, utf8Column: 4), 2)
|
|
}
|
|
|
|
func testLineTableEditing() {
|
|
var t = LineTable("")
|
|
t.replace(fromLine: 0, utf16Offset: 0, utf16Length: 0, with: "a")
|
|
XCTAssertEqual(t, LineTable("a"))
|
|
t.replace(fromLine: 0, utf16Offset: 0, utf16Length: 0, with: "cb")
|
|
XCTAssertEqual(t, LineTable("cba"))
|
|
t.replace(fromLine: 0, utf16Offset: 1, utf16Length: 1, with: "d")
|
|
XCTAssertEqual(t, LineTable("cda"))
|
|
t.replace(fromLine: 0, utf16Offset: 3, utf16Length: 0, with: "e")
|
|
XCTAssertEqual(t, LineTable("cdae"))
|
|
t.replace(fromLine: 0, utf16Offset: 3, utf16Length: 1, with: "")
|
|
XCTAssertEqual(t, LineTable("cda"))
|
|
|
|
t = LineTable("a")
|
|
t.replace(fromLine: 0, utf16Offset: 0, utf16Length: 0, with: "\n")
|
|
XCTAssertEqual(t, LineTable("\na"))
|
|
t.replace(fromLine: 1, utf16Offset: 0, utf16Length: 0, with: "\n")
|
|
XCTAssertEqual(t, LineTable("\n\na"))
|
|
t.replace(fromLine: 2, utf16Offset: 1, utf16Length: 0, with: "\n")
|
|
XCTAssertEqual(t, LineTable("\n\na\n"))
|
|
|
|
t = LineTable(
|
|
"""
|
|
abcd
|
|
efgh
|
|
"""
|
|
)
|
|
|
|
t.replace(fromLine: 0, utf16Offset: 2, toLine: 1, utf16Offset: 1, with: "x")
|
|
XCTAssertEqual(t, LineTable("abxfgh"))
|
|
|
|
t.replace(fromLine: 0, utf16Offset: 2, toLine: 0, utf16Offset: 4, with: "p\nq\n")
|
|
XCTAssertEqual(t, LineTable("abp\nq\ngh"))
|
|
}
|
|
}
|