Files
sourcekit-lsp/Tests/SourceKitLSPTests/SwiftCompletetionSnippetTests.swift

310 lines
9.8 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 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
//
//===----------------------------------------------------------------------===//
@_spi(SourceKitLSP) import LanguageServerProtocol
import SKLogging
import SKTestSupport
import SourceKitLSP
import SwiftExtensions
import XCTest
final class SwiftCompletionSnippetTests: SourceKitLSPTestCase {
private var snippetCapabilities = ClientCapabilities(
textDocument: TextDocumentClientCapabilities(
completion: TextDocumentClientCapabilities.Completion(
completionItem: TextDocumentClientCapabilities.Completion.CompletionItem(snippetSupport: true)
)
)
)
func testKeywordIfProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let ifItem = try XCTUnwrap(completions.items.first(where: { $0.label == "if" }))
XCTAssertEqual(ifItem.kind, .keyword)
XCTAssertEqual(ifItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(ifItem.insertText)
XCTAssertTrue(insertText.contains("${1:condition}"))
XCTAssertTrue(insertText.contains("${0:body}"))
}
func testKeywordForProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let forItem = try XCTUnwrap(completions.items.first(where: { $0.label == "for" }))
XCTAssertEqual(forItem.kind, .keyword)
XCTAssertEqual(forItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(forItem.insertText)
XCTAssertTrue(insertText.contains("${1:item}"))
XCTAssertTrue(insertText.contains("${2:sequence}"))
}
func testKeywordWhileProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let whileItem = try XCTUnwrap(completions.items.first(where: { $0.label == "while" }))
XCTAssertEqual(whileItem.kind, .keyword)
XCTAssertEqual(whileItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(whileItem.insertText)
XCTAssertTrue(insertText.contains("${1:condition}"))
}
func testKeywordGuardProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let guardItem = try XCTUnwrap(completions.items.first(where: { $0.label == "guard" }))
XCTAssertEqual(guardItem.kind, .keyword)
XCTAssertEqual(guardItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(guardItem.insertText)
XCTAssertTrue(insertText.contains("${1:condition}"))
XCTAssertTrue(insertText.contains("else"))
}
func testKeywordSwitchProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let switchItem = try XCTUnwrap(completions.items.first(where: { $0.label == "switch" }))
XCTAssertEqual(switchItem.kind, .keyword)
XCTAssertEqual(switchItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(switchItem.insertText)
XCTAssertTrue(insertText.contains("${1:value}"))
XCTAssertTrue(insertText.contains("case"))
// Expect `case` to be not indented and the body placeholder to exist (indentation tested elsewhere).
XCTAssertTrue(insertText.contains("case ${2:pattern}:"))
XCTAssertTrue(insertText.contains("${0:body}"))
}
func testKeywordRepeatProvidesSnippet() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let repeatItem = try XCTUnwrap(completions.items.first(where: { $0.label == "repeat" }))
XCTAssertEqual(repeatItem.kind, .keyword)
XCTAssertEqual(repeatItem.insertTextFormat, .snippet)
let insertText = try XCTUnwrap(repeatItem.insertText)
XCTAssertTrue(insertText.contains("while"))
}
func testKeywordWithoutSnippetSupport() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
// Client without snippet support should get plain keywords
let testClient = try await TestSourceKitLSPClient()
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let ifItem = try XCTUnwrap(completions.items.first(where: { $0.label == "if" }))
XCTAssertEqual(ifItem.kind, .keyword)
XCTAssertEqual(ifItem.insertTextFormat, .plain)
XCTAssertEqual(ifItem.insertText, "if")
}
func testInsertTextAndTextEditAreConsistent() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
for item in completions.items {
guard let insertText = item.insertText else { continue }
// Skip SourceKit's implicit method call labels (e.g. "funcName()")
if item.label.contains("(") && item.label.contains(")") { continue }
if case .textEdit(let te) = item.textEdit {
XCTAssertEqual(insertText, te.newText, "insertText and textEdit.newText differ for item '\(item.label)'")
}
}
}
func testKeywordSnippetUsesInferredSpacesIndentation() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
let positions = testClient.openDocument(
"""
func test() {
let a = 1
let b = 2
1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let ifItem = try XCTUnwrap(completions.items.first(where: { $0.label == "if" }))
let insertText = try XCTUnwrap(ifItem.insertText)
// Expect newline + two spaces before the final placeholder
XCTAssertTrue(
insertText.contains("\n ${0:body}"),
"expected two-space indentation in snippet, got: '\(insertText)'"
)
}
func testKeywordSnippetUsesInferredTabsIndentation() async throws {
try await SkipUnless.sourcekitdSupportsPlugin()
let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
let uri = DocumentURI(for: .swift)
// Use raw tabs \t for indentation to ensure server picks up Tab style.
let positions = testClient.openDocument(
"""
func test() {
\tlet a = 1
\tlet b = 2
\t1️⃣
}
""",
uri: uri
)
let completions = try await testClient.send(
CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
)
let ifItem = try XCTUnwrap(completions.items.first(where: { $0.label == "if" }))
let insertText = try XCTUnwrap(ifItem.insertText)
// Expect newline + tab then the body placeholder
XCTAssertTrue(insertText.contains("\n\t${0:body}"), "expected tab indentation in snippet, got: '\(insertText)'")
}
}