//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 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
@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions
import XCTest

final class SwiftCompletionTests: SourceKitLSPTestCase {
  // MARK: - Helpers

  private var snippetCapabilities = ClientCapabilities(
    textDocument: TextDocumentClientCapabilities(
      completion: TextDocumentClientCapabilities.Completion(
        completionItem: TextDocumentClientCapabilities.Completion.CompletionItem(snippetSupport: true)
      )
    )
  )

  private var insertReplaceEditCapabilities = ClientCapabilities(
    textDocument: TextDocumentClientCapabilities(
      completion: TextDocumentClientCapabilities.Completion(
        completionItem: TextDocumentClientCapabilities.Completion.CompletionItem(insertReplaceSupport: true)
      )
    )
  )

  private var insertReplaceEditAndSnippetCapabilities = ClientCapabilities(
    textDocument: TextDocumentClientCapabilities(
      completion: TextDocumentClientCapabilities.Completion(
        completionItem: TextDocumentClientCapabilities.Completion.CompletionItem(
          snippetSupport: true,
          insertReplaceSupport: true
        )
      )
    )
  )

  // MARK: - Tests

  func testCompletionBasic() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()
    try await SkipUnless.sourcekitdSupportsFullDocumentationInCompletion()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)

    let positions = testClient.openDocument(
      """
      struct S {
        /// Documentation for `abc`.
        ///
        /// _More_ documentation for `abc`.
        ///
        /// Usage:
        /// ```swift
        /// S().abc
        /// ```
        var abc: Int

        func test(a: Int) {
          self.1️⃣abc
      2️⃣  }

        func test(_ b: Int) {
          self.abc
        }
      }
      """,
      uri: uri
    )

    let selfDot = try await testClient.send(
      CompletionRequest(
        textDocument: TextDocumentIdentifier(uri),
        position: positions["1️⃣"]
      )
    )

    XCTAssertTrue(selfDot.isIncomplete)
    XCTAssertGreaterThanOrEqual(selfDot.items.count, 2)
    let abc = selfDot.items.first { $0.label == "abc" }
    XCTAssertNotNil(abc)
    if let abc = abc {
      XCTAssertEqual(abc.kind, .property)
      XCTAssertEqual(abc.detail, "Int")
      assertMarkdown(
        documentation: abc.documentation,
        expected: """
          Documentation for `abc`.

          _More_ documentation for `abc`.

          Usage:
          ```swift
          S().abc
          ```
          """
      )
      XCTAssertEqual(abc.filterText, "abc")
      XCTAssertEqual(abc.textEdit, .textEdit(TextEdit(range: Range(positions["1️⃣"]), newText: "abc")))
      XCTAssertEqual(abc.insertText, "abc")
      XCTAssertEqual(abc.insertTextFormat, .plain)
    }

    for columnOffset in 1...3 {
      let offsetPosition = positions["1️⃣"].adding(columns: columnOffset)
      let inIdent = try await testClient.send(
        CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: offsetPosition)
      )
      guard let abc = inIdent.items.first(where: { $0.label == "abc" }) else {
        XCTFail("No completion item with label 'abc'")
        return
      }

      // If we switch to server-side filtering this will change.
      XCTAssertEqual(abc.kind, .property)
      XCTAssertEqual(abc.detail, "Int")
      assertMarkdown(
        documentation: abc.documentation,
        expected: """
          Documentation for `abc`.

          _More_ documentation for `abc`.

          Usage:
          ```swift
          S().abc
          ```
          """
      )
      XCTAssertEqual(abc.filterText, "abc")
      XCTAssertEqual(abc.textEdit, .textEdit(TextEdit(range: positions["1️⃣"]..<offsetPosition, newText: "abc")))
      XCTAssertEqual(abc.insertText, "abc")
      XCTAssertEqual(abc.insertTextFormat, .plain)
    }

    let after = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    XCTAssertNotEqual(after, selfDot)
  }

  func testCompletionSnippetSupport() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        /// Documentation for `abc`.
        var abc: Int

        func test(a: Int) {
          self.1️⃣abc
        }

        func test(_ b: Int) {
          self.2️⃣abc
        }
      }
      """,
      uri: uri
    )

    func getTestMethodCompletion(_ position: Position, label: String) async throws -> CompletionItem? {
      let selfDot = try await testClient.send(
        CompletionRequest(
          textDocument: TextDocumentIdentifier(uri),
          position: position
        )
      )
      return selfDot.items.first { $0.label == label }
    }

    var test = try await getTestMethodCompletion(positions["1️⃣"], label: "test(a: Int)")
    XCTAssertNotNil(test)
    if let test = test {
      XCTAssertEqual(test.kind, .method)
      XCTAssertEqual(test.detail, "Void")
      XCTAssertEqual(test.filterText, "test(a:)")
      XCTAssertEqual(test.textEdit, .textEdit(TextEdit(range: Range(positions["1️⃣"]), newText: "test(a: ${1:Int})")))
      XCTAssertEqual(test.insertText, "test(a: ${1:Int})")
      XCTAssertEqual(test.insertTextFormat, .snippet)
    }

    test = try await getTestMethodCompletion(positions["2️⃣"], label: "test(b: Int)")
    XCTAssertNotNil(test)
    if let test = test {
      XCTAssertEqual(test.kind, .method)
      XCTAssertEqual(test.detail, "Void")
      XCTAssertEqual(test.filterText, "test(:)")
      XCTAssertEqual(test.textEdit, .textEdit(TextEdit(range: Range(positions["2️⃣"]), newText: "test(${1:Int})")))
      XCTAssertEqual(test.insertText, "test(${1:Int})")
      XCTAssertEqual(test.insertTextFormat, .snippet)
    }
  }

  func testCompletionInsertReplaceEditSupport() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        var abc: Int
        var def: S

        func test() {
          self.1️⃣ab2️⃣c3️⃣
          self.4️⃣ab5️⃣c6️⃣+1
          self.7️⃣ab8️⃣c9️⃣()
          self.🔟ab0️⃣cℹ️.def
        }
      }
      """,
      uri: uri
    )

    func assertABCInsertReplace(_ start: String, _ cursor: String, _ end: String) async throws {
      let completions = try await testClient.send(
        CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions[cursor])
      )

      guard let abc = completions.items.first(where: { $0.label == "abc" }) else {
        XCTFail("No completion item with label 'abc'")
        return
      }

      XCTAssertEqual(
        abc.textEdit,
        .insertReplaceEdit(
          InsertReplaceEdit(
            newText: "abc",
            insert: positions[start]..<positions[cursor],
            replace: positions[start]..<positions[end]
          )
        )
      )
    }

    // Replacement should stop before whitespace.
    try await assertABCInsertReplace("1️⃣", "2️⃣", "3️⃣")
    // Replacement should stop before an operator token.
    try await assertABCInsertReplace("4️⃣", "5️⃣", "6️⃣")
    // Replacement should stop before punctuation like '('.
    try await assertABCInsertReplace("7️⃣", "8️⃣", "9️⃣")
    // Replacement should stop before member access '.'.
    try await assertABCInsertReplace("🔟", "0️⃣", "ℹ️")
  }

  func testCompletionNoInsertReplaceEditAtEndOfIdentifier() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        var foobar: Int

        func test() {
          self.1️⃣foo2️⃣
        }
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )

    guard let abc = completions.items.first(where: { $0.label == "foobar" }) else {
      XCTFail("No completion item with label 'foobar'")
      return
    }

    XCTAssertEqual(abc.textEdit, .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "foobar")))
  }

  func testCompletionNoInsertReplaceEditAtEndOfIdentifierWithFollowingStatement() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        let bar: Int
      }

      func test() {
        let x = Foo(bar: 1)
        x.1️⃣ba2️⃣
        print("abc")
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )

    guard let bar = completions.items.first(where: { $0.label == "bar" }) else {
      XCTFail("No completion item with label 'bar'")
      return
    }

    XCTAssertEqual(bar.textEdit, .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "bar")))
  }

  func testCompletionNoSnippetSupport() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        /// Documentation for `abc`.
        var abc: Int

        func test(a: Int) {
          self.1️⃣abc
        }

        func test(_ b: Int) {
          self.2️⃣abc
        }
      }
      """,
      uri: uri
    )

    func getTestMethodCompletion(_ position: Position, label: String) async throws -> CompletionItem? {
      let selfDot = try await testClient.send(
        CompletionRequest(
          textDocument: TextDocumentIdentifier(uri),
          position: position
        )
      )
      return selfDot.items.first { $0.label == label }
    }

    var test = try await getTestMethodCompletion(positions["1️⃣"], label: "test(a: Int)")
    XCTAssertNotNil(test)
    if let test = test {
      XCTAssertEqual(test.kind, .method)
      XCTAssertEqual(test.detail, "Void")
      XCTAssertEqual(test.filterText, "test(a:)")
      XCTAssertEqual(test.textEdit, .textEdit(TextEdit(range: Range(positions["1️⃣"]), newText: "test(a: )")))
      XCTAssertEqual(test.insertText, "test(a: )")
      XCTAssertEqual(test.insertTextFormat, .plain)
    }

    test = try await getTestMethodCompletion(positions["2️⃣"], label: "test(b: Int)")
    XCTAssertNotNil(test)
    if let test = test {
      XCTAssertEqual(test.kind, .method)
      XCTAssertEqual(test.detail, "Void")
      XCTAssertEqual(test.filterText, "test(:)")
      XCTAssertEqual(test.textEdit, .textEdit(TextEdit(range: Range(positions["2️⃣"]), newText: "test()")))
      XCTAssertEqual(test.insertText, "test()")
      XCTAssertEqual(test.insertTextFormat, .plain)
    }
  }

  func testCompletionPositionServerFilter() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    testClient.openDocument("foo", uri: uri)

    for col in 0...3 {
      let inOrAfterFoo = try await testClient.send(
        CompletionRequest(
          textDocument: TextDocumentIdentifier(uri),
          position: Position(line: 0, utf16index: col)
        )
      )
      XCTAssertTrue(inOrAfterFoo.isIncomplete)
      XCTAssertFalse(inOrAfterFoo.items.isEmpty)
    }

    let outOfRange1 = try await testClient.send(
      CompletionRequest(
        textDocument: TextDocumentIdentifier(uri),
        position: Position(line: 0, utf16index: 4)
      )
    )
    XCTAssertTrue(outOfRange1.isIncomplete)

    let outOfRange2 = try await testClient.send(
      CompletionRequest(
        textDocument: TextDocumentIdentifier(uri),
        position: Position(line: 1, utf16index: 0)
      )
    )
    XCTAssertTrue(outOfRange2.isIncomplete)
  }

  func testCompletionOptional() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        let bar: Int
      }
      let a: Foo? = Foo(bar: 1)
      a1️⃣.2️⃣ba
      """,
      uri: uri
    )

    for columnOffset in 0...2 {
      let offsetPosition = positions["2️⃣"].adding(columns: columnOffset)
      let response = try await testClient.send(
        CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: offsetPosition)
      )

      guard let item = response.items.first(where: { $0.label.contains("bar") }) else {
        XCTFail("No completion item with label 'bar'")
        return
      }
      XCTAssertEqual(item.filterText, ".bar")
      XCTAssertEqual(
        item.textEdit,
        .textEdit(
          TextEdit(range: positions["1️⃣"]..<offsetPosition, newText: "?.bar")
        )
      )
    }
  }

  func testCompletionOverride() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      class Base {
        func foo() {}
      }
      class C: Base {
        1️⃣func 2️⃣   // don't delete trailing space in this file
      }
      """,
      uri: uri
    )

    let response = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    guard let item = response.items.first(where: { $0.label == "foo()" }) else {
      XCTFail("No completion item with label 'foo()'")
      return
    }
    XCTAssertEqual(item.filterText, "func foo()")
    XCTAssertEqual(
      item.textEdit,
      .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "override func foo() {\n\n}"))
    )
  }

  func testCompletionOverrideInNewLine() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      class Base {
        func foo() {}
      }
      class C: Base {
        func
        1️⃣  // don't delete trailing space in this file
      }
      """,
      uri: uri
    )

    let response = try await testClient.send(
      CompletionRequest(
        textDocument: TextDocumentIdentifier(uri),
        position: positions["1️⃣"]
      )
    )
    guard let item = response.items.first(where: { $0.label == "foo()" }) else {
      XCTFail("No completion item with label 'foo()'")
      return
    }
    // If the edit would cross multiple lines, we are currently not replacing any text. It's not technically correct but the best we can do.
    XCTAssertEqual(item.filterText, "foo()")
    XCTAssertEqual(
      item.textEdit,
      .textEdit(TextEdit(range: Range(positions["1️⃣"]), newText: "override func foo() {\n\n}"))
    )
  }

  func testRefilterAfterIncompleteResults() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        func fooAbc() {}
        func fooBcd() {}
        func fooCde() {}
        func fooDef() {}
        func fooGoop() {}
        func test() {
      1️⃣    self.f2️⃣cdez
        }
      }
      """,
      uri: uri
    )

    assertEqual(
      5,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"],
            context: CompletionContext(triggerKind: .invoked)
          )
        )
      )
    )

    assertEqual(
      3,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 1),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )
    assertEqual(
      2,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 2),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )
    assertEqual(
      1,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 3),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )
    assertEqual(
      0,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 4),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )
    assertEqual(
      2,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 2),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    assertEqual(
      1,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["2️⃣"].adding(columns: 3),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    // Trigger kind changed => OK (200 is maxResults since we're outside the member completion)
    assertEqual(
      200,
      try await testClient.send(
        CompletionRequest(
          textDocument: TextDocumentIdentifier(uri),
          position: positions["1️⃣"],
          context: CompletionContext(triggerKind: .invoked)
        )
      ).items.count
    )
  }

  func testRefilterAfterIncompleteResultsWithEdits() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        func fooAbc() {}
        func fooBcd() {}
        func fooCde() {}
        func fooDef() {}
        func fooGoop() {}
        func test() {
          self.f1️⃣z
        }
      }
      """,
      uri: uri
    )

    // 'f'
    assertEqual(
      5,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"],
            context: CompletionContext(triggerKind: .invoked)
          )
        )
      )
    )

    // 'fz'
    assertEqual(
      0,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"].adding(columns: 1),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: 1),
        contentChanges: [
          .init(range: positions["1️⃣"]..<(positions["1️⃣"].adding(columns: 1)), text: "A ")
        ]
      )
    )

    // 'fA'
    assertEqual(
      1,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"].adding(columns: 1),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    // 'fA '
    assertEqual(
      try await testClient.send(
        CompletionRequest(
          textDocument: TextDocumentIdentifier(uri),
          position: positions["1️⃣"].adding(columns: 2),
          context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
        )
      ).items,
      []
    )

    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: 1),
        contentChanges: [
          .init(range: positions["1️⃣"]..<(positions["1️⃣"].adding(columns: 1)), text: "Ab")
        ]
      )
    )

    // 'fAb'
    assertEqual(
      1,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"].adding(columns: 1),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: 1),
        contentChanges: [
          .init(range: positions["1️⃣"]..<(positions["1️⃣"].adding(columns: 1)), text: "")
        ]
      )
    )

    // 'fb'
    assertEqual(
      2,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"].adding(columns: 1),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )

    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: 1),
        contentChanges: [
          .init(range: Range(positions["1️⃣"].adding(columns: 1)), text: "d")
        ]
      )
    )

    // 'fbd'
    assertEqual(
      1,
      countFs(
        try await testClient.send(
          CompletionRequest(
            textDocument: TextDocumentIdentifier(uri),
            position: positions["1️⃣"].adding(columns: 2),
            context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
          )
        )
      )
    )
  }

  /// Regression test for https://bugs.swift.org/browse/SR-13561 to make sure the a session
  /// close waits for its respective open to finish to prevent a session geting stuck open.
  func testSessionCloseWaitsforOpen() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct S {
        func forSomethingCrazy() {}
        func forSomethingCool() {}
        func test() {
          self.forS1️⃣ome
        }
        func print() {}
        func anotherOne() {
          self.prin2️⃣
        }
      }
      """,
      uri: uri
    )

    let forSomeComplete = CompletionRequest(
      textDocument: TextDocumentIdentifier(uri),
      position: positions["1️⃣"],
      context: CompletionContext(triggerKind: .invoked)
    )
    let printComplete = CompletionRequest(
      textDocument: TextDocumentIdentifier(uri),
      position: positions["2️⃣"],
      context: CompletionContext(triggerKind: .invoked)
    )

    // Code completion for "self.forSome"
    async let forSomeResult = testClient.send(forSomeComplete)

    // Code completion for "self.prin", previously could immediately invalidate
    // the previous request.
    async let printResult = testClient.send(printComplete)

    assertEqual(2, countFs(try await forSomeResult))
    assertEqual(1, try await printResult.items.count)

    // Try code completion for "self.forSome" again to verify that it still works.
    let result = try await testClient.send(forSomeComplete)
    XCTAssertEqual(2, countFs(result))
  }

  func testCodeCompleteSwiftPackage() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let project = try await SwiftPMTestProject(
      files: [
        "a.swift": """
        struct A {
          func method(a b: Int) {}
        }
        """,
        "b.swift": """
        func test(a: A) {
          a.1️⃣
        }
        """,
      ],
      // We don't want to test behavior based on fallback settings. Increase the buildSettingsTimeout to ensure we always get proper build settings.
      options: .testDefault(buildSettingsTimeout: defaultTimeoutDuration)
    )
    let (uri, positions) = try project.openDocument("b.swift")

    let testPosition = positions["1️⃣"]
    let results = try await project.testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: testPosition)
    )

    XCTAssertEqual(
      results.items.clearingUnstableValues,
      [
        CompletionItem(
          label: "method(a: Int)",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "method(a:)",
          insertText: "method(a: )",
          insertTextFormat: .plain,
          textEdit: .textEdit(
            TextEdit(
              range: Range(testPosition),
              newText: "method(a: )"
            )
          )
        ),
        CompletionItem(
          label: "self",
          kind: .keyword,
          detail: "A",
          deprecated: false,
          filterText: "self",
          insertText: "self",
          insertTextFormat: .plain,
          textEdit: .textEdit(
            TextEdit(range: Range(testPosition), newText: "self")
          )
        ),
      ]
    )
  }

  func testTriggerFromIncompleteAfterStartingStringLiteral() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foo(_ x: String) {}

      func test() {
        foo1️⃣
      }
      """,
      uri: uri
    )

    // The following is a pattern that VS Code sends. Make sure we don't return an error.
    // - Insert `()``, changing the line to `foo()``
    // - Invoke code completion after `(`
    // - Insert `""`, changing the line to `foo("")`
    // - Insert `d` inside the string literal, changing the line to `foo("d")`
    // - Ask for completion with the `triggerFromIncompleteCompletions` flag set.
    // Since this isn't actually re-filtering but is a completely new code completion session. When we detect this, we
    // should just start a new session and return the results.
    var position = positions["1️⃣"]
    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: position.utf16index),
        contentChanges: [TextDocumentContentChangeEvent(range: Range(position), text: "()")]
      )
    )
    position.utf16index += 1
    let initialCompletionResults = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: position)
    )
    // Test that we get the "abc" result which makes VS Code think that we are still in the same completion session when doing hte second completion.
    XCTAssert(initialCompletionResults.items.contains(where: { $0.label == #""abc""# }))
    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: position.utf16index),
        contentChanges: [TextDocumentContentChangeEvent(range: Range(position), text: "\"\"")]
      )
    )
    position.utf16index += 1
    testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(uri, version: position.utf16index),
        contentChanges: [TextDocumentContentChangeEvent(range: Range(position), text: "d")]
      )
    )
    let secondCompletionResults = try await testClient.send(
      CompletionRequest(
        textDocument: TextDocumentIdentifier(uri),
        position: position,
        context: CompletionContext(triggerKind: .triggerFromIncompleteCompletions)
      )
    )
    // We shouldn't be getting code completion results for inside the string literal.
    XCTAssert(secondCompletionResults.items.isEmpty)
  }

  func testNonAsciiCompletionFilter() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        func 👨‍👩‍👦👨‍👩‍👦() {}
        func test() {
          self.1️⃣👨‍👩‍👦2️⃣
        }
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues,
      [
        CompletionItem(
          label: "👨‍👩‍👦👨‍👩‍👦()",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "👨‍👩‍👦👨‍👩‍👦()",
          insertText: "👨‍👩‍👦👨‍👩‍👦()",
          insertTextFormat: .plain,
          textEdit: .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "👨‍👩‍👦👨‍👩‍👦()"))
        )
      ]
    )
  }

  func testIndentTrailingClosureBody() async throws {
    // sourcekitd returns a completion item with an already expanded closure here. Make sure that we add indentation to
    // the body.
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
        func myasync(execute work: () -> Void) {}
      }

      func test(x: MyArray) {
          x.1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myasync {") },
      [
        CompletionItem(
          label: "myasync { code }",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "myasync",
          insertText: #"""
            myasync {
                ${1:code}
            }
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myasync {
                    ${1:code}
                }
                """#
            )
          )
        )
      ]
    )
  }

  func testIndentTrailingClosureBodyOnOptional() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
        func myasync(execute work: () -> Void) {}
      }

      func test(x: MyArray?) {
          x1️⃣.2️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myasync {") },
      [
        CompletionItem(
          label: "myasync { code }",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: ".myasync",
          insertText: #"""
            ?.myasync {
                ${1:code}
            }
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: positions["1️⃣"]..<positions["2️⃣"],
              newText: #"""
                ?.myasync {
                    ${1:code}
                }
                """#
            )
          )
        )
      ]
    )
  }

  func testExpandClosurePlaceholder() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
          func myMap(_ body: (Int) -> Bool) {}
      }
      func test(x: MyArray) {
          x.1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myMap") },
      [
        CompletionItem(
          label: "myMap(body: (Int) -> Bool)",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "myMap(:)",
          insertText: #"""
            myMap(${1:{ ${2:Int} in ${3:Bool} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMap(${1:{ ${2:Int} in ${3:Bool} \}})
                """#
            )
          )
        )
      ]
    )
  }

  func testCompletionWithExistingTrailingClosureDoesNotTrimAtSnippetBrace() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
          func myMap(_ body: (Int) -> Bool) {}
      }
      func test(x: MyArray) {
          x.1️⃣myM2️⃣ { _ in true }
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("myMap") })
    XCTAssertEqual(
      completion.textEdit,
      .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "myMap"))
    )
  }

  func testExpandClosurePlaceholderOnOptional() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
          func myMap(_ body: (Int) -> Bool) {}
      }
      func test(x: MyArray?) {
          x1️⃣.2️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myMap") },
      [
        CompletionItem(
          label: "myMap(body: (Int) -> Bool)",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: ".myMap(:)",
          insertText: #"""
            ?.myMap(${1:{ ${2:Int} in ${3:Bool} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: positions["1️⃣"]..<positions["2️⃣"],
              newText: #"""
                ?.myMap(${1:{ ${2:Int} in ${3:Bool} \}})
                """#
            )
          )
        )
      ]
    )
  }

  func testExpandMultipleClosurePlaceholders() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
          func myMap(_ body: (Int) -> Bool, _ second: (Int) -> String) {}
      }
      func test(x: MyArray) {
          x.1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myMap") },
      [
        CompletionItem(
          label: "myMap(body: (Int) -> Bool, second: (Int) -> String)",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "myMap(::)",
          insertText: #"""
            myMap(${1:{ ${2:Int} in ${3:Bool} \}}, ${4:{ ${5:Int} in ${6:String} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMap(${1:{ ${2:Int} in ${3:Bool} \}}, ${4:{ ${5:Int} in ${6:String} \}})
                """#
            )
          )
        )
      ]
    )
  }

  func testExpandMultipleClosurePlaceholdersWithLabel() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
          func myMap(_ body: (Int) -> Bool, second: (Int) -> String) {}
      }
      func test(x: MyArray) {
          x.1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myMap") },
      [
        CompletionItem(
          label: "myMap(body: (Int) -> Bool, second: (Int) -> String)",
          kind: .method,
          detail: "Void",
          deprecated: false,
          filterText: "myMap(:second:)",
          insertText: #"""
            myMap(${1:{ ${2:Int} in ${3:Bool} \}}, second: ${4:{ ${5:Int} in ${6:String} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMap(${1:{ ${2:Int} in ${3:Bool} \}}, second: ${4:{ ${5:Int} in ${6:String} \}})
                """#
            )
          )
        )
      ]
    )
  }

  func testInferIndentationWhenExpandingClosurePlaceholder() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct MyArray {
        func myMap(_ body: (Int) -> Bool) -> Int {
          return 1
        }
      }
      func test(x: MyArray) {
        x.1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.filter { $0.label.contains("myMap") }.clearingUnstableValues,
      [
        CompletionItem(
          label: "myMap(body: (Int) -> Bool)",
          kind: .method,
          detail: "Int",
          deprecated: false,
          filterText: "myMap(:)",
          insertText: #"""
            myMap(${1:{ ${2:Int} in ${3:Bool} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMap(${1:{ ${2:Int} in ${3:Bool} \}})
                """#
            )
          )
        )
      ]
    )
  }

  func testExpandMacroClosurePlaceholder() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      @freestanding(expression)
      macro myMacroExpr(fn: (Int) -> String) = #externalMacro(module: "", type: "")

      @freestanding(declaration)
      macro myMacroDecl(fn1: (Int) -> String, fn2: () -> Void) = #externalMacro(module: "", type: "")

      func test() {
          #1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.filter { $0.label.contains("myMacro") },
      [
        CompletionItem(
          label: "myMacroDecl(fn1: (Int) -> String, fn2: () -> Void)",
          kind: .value,
          detail: "Declaration Macro",
          deprecated: false,
          filterText: "myMacroDecl(fn1:fn2:)",
          insertText: #"""
            myMacroDecl(fn1: ${1:{ ${2:Int} in ${3:String} \}}, fn2: ${4:{ ${5:Void} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMacroDecl(fn1: ${1:{ ${2:Int} in ${3:String} \}}, fn2: ${4:{ ${5:Void} \}})
                """#
            )
          )
        ),
        CompletionItem(
          label: "myMacroExpr(fn: (Int) -> String)",
          kind: .value,
          detail: "Void",
          deprecated: false,
          filterText: "myMacroExpr(fn:)",
          insertText: #"""
            myMacroExpr(fn: ${1:{ ${2:Int} in ${3:String} \}})
            """#,
          insertTextFormat: .snippet,
          textEdit: .textEdit(
            TextEdit(
              range: Range(positions["1️⃣"]),
              newText: #"""
                myMacroExpr(fn: ${1:{ ${2:Int} in ${3:String} \}})
                """#
            )
          )
        ),
      ]
    )
  }

  func testCompletionScoring() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()

    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        func makeBool() -> Bool { true }
        func makeInt() -> Int { 1 }
        func makeString() -> String { "" }
      }
      func test(foo: Foo) {
        let x: Int = foo.make1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(
      completions.items.clearingUnstableValues.map(\.label),
      ["makeInt()", "makeBool()", "makeString()"]
    )
  }

  func testCompletionItemResolve() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()
    try await SkipUnless.sourcekitdSupportsFullDocumentationInCompletion()

    let capabilities = ClientCapabilities(
      textDocument: TextDocumentClientCapabilities(
        completion: TextDocumentClientCapabilities.Completion(
          completionItem: TextDocumentClientCapabilities.Completion.CompletionItem(
            resolveSupport: TextDocumentClientCapabilities.Completion.CompletionItem.ResolveSupportProperties(
              properties: ["documentation"]
            )
          )
        )
      )
    )

    let testClient = try await TestSourceKitLSPClient(capabilities: capabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        /// Creates a true value
        func makeBool() -> Bool { true }
      }
      func test(foo: Foo) {
        foo.make1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    let item = try XCTUnwrap(completions.items.only)
    XCTAssertNil(item.documentation)
    let resolvedItem = try await testClient.send(CompletionItemResolveRequest(item: item))
    assertMarkdown(
      documentation: resolvedItem.documentation,
      expected: "Creates a true value"
    )
  }

  func testCompletionBriefDocumentationFallback() async throws {
    try await SkipUnless.sourcekitdSupportsPlugin()
    try await SkipUnless.sourcekitdSupportsFullDocumentationInCompletion()

    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)

    // We test completion for result builder build functions since they don't have full documentation
    // but still have brief documentation.
    let positions = testClient.openDocument(
      """
      @resultBuilder
      struct AnyBuilder {
        static func 1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    let item = try XCTUnwrap(completions.items.filter { $0.label.contains("buildBlock") }.only)
    assertMarkdown(
      documentation: item.documentation,
      expected: "Required by every result builder to build combined results from statement blocks"
    )
  }

  func testCallDefaultedArguments() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Foo {
        func makeBool(value: Bool = true) -> Bool { value }
      }
      func test(foo: Foo) {
        foo.make1️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(completions.items.map(\.insertText), ["makeBool()", "makeBool(value: )"])
  }

  func testCompletionUsingCompileFlagsTxt() async throws {
    let compileFlags =
      if let defaultSDKPath {
        """
        -DFOO
        -sdk
        \(defaultSDKPath)
        """
      } else {
        "-DFOO"
      }

    let project = try await MultiFileTestProject(
      files: [
        "test.swift": """
        func test() {
          #if FOO
          let myVar: String
          #else
          let myVar: Int
          #endif
          print(myVar1️⃣)
        }
        """,
        "compile_flags.txt": compileFlags,
      ]
    )
    let (uri, positions) = try project.openDocument("test.swift")
    let completions = try await project.testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    XCTAssertEqual(completions.items.only?.detail, "String")
  }

  func testSuggestInMemoryFunctionsFromFilesWithinSameModule() async throws {
    let project = try await SwiftPMTestProject(
      files: [
        "First.swift": """
        myFancyFunc1️⃣
        """,
        "Second.swift": "2️⃣",
      ],
      // We don't want to test behavior based on fallback settings. Increase the buildSettingsTimeout to ensure we always get proper build settings.
      options: .testDefault(buildSettingsTimeout: defaultTimeoutDuration)
    )

    let (secondUri, secondPositions) = try project.openDocument("Second.swift")
    project.testClient.send(
      DidChangeTextDocumentNotification(
        textDocument: VersionedTextDocumentIdentifier(secondUri, version: 2),
        contentChanges: [
          TextDocumentContentChangeEvent(
            range: Range(secondPositions["2️⃣"]),
            text: """
              func myFancyFunction() {}
              """
          )
        ]
      )
    )

    // Synchronize to make sure that the edit to Second.swift has been processed since opening First.swift and the
    // completion request do not have any dependencies on the edit of Second.swift.
    try await project.testClient.send(SynchronizeRequest())
    let (firstUri, firstPositions) = try project.openDocument("First.swift")
    let completions = try await project.testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(firstUri), position: firstPositions["1️⃣"])
    )
    XCTAssert(completions.items.contains(where: { $0.label.contains("myFancyFunction") }))
  }

  func testSubscriptCompletions() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foo(x: [Int: Int]) {
        x[1️⃣
      }
      """,
      uri: uri
    )
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    assertContains(completions.items.map(\.label), "[key: Int, default: Int]")
  }

  func testArgumentCompletionContainsClosingParenthesisIfNotPresentInEditor() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foo() {
        foo(1️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.only)
    XCTAssertEqual(completion.textEdit, .textEdit(TextEdit(range: Range(positions["1️⃣"]), newText: ")")))
  }

  func testArgumentCompletionReplacesExistingClosingParenthesis() async throws {
    // See https://github.com/swiftlang/sourcekit-lsp/issues/782 for why this is important
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foo() {
        foo(1️⃣)2️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.only)
    XCTAssertEqual(completion.textEdit, .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: ")")))
  }

  func testArgumentCompletionReplacesExistingClosingParenthesisInNestedCall() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foo() {
        foo(foo(1️⃣)2️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.only)
    XCTAssertEqual(completion.textEdit, .textEdit(TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: ")")))
  }

  func testFunctionCompletionDoesNotInsertArgumentsIfTheyAlreadyExist() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(x: 5, y: 3)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionDoesNotInsertArgumentsIfTheyAlreadyExistWithSnippets() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(x: 5, y: 3)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
    XCTAssertEqual(completion.insertTextFormat, .plain)
  }

  func testFunctionCompletionTreatsExistingParensAfterWhitespaceAsExistingCall() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣   (x: 5, y: 3)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionTreatsExistingMultilineCallAsExistingCall() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(
          x: 5,
          y: 3
        )
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionDoesNotTreatNextLineParensAsExistingCall() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣
        (x: 5, y: 3)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar(x: , y: )")
  }

  func testFunctionCompletionReplacesExistingEmptyParens() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣()3️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["3️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar(x: , y: )")
  }

  func testFunctionCompletionReplacesExistingEmptyParensWithSnippets() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: snippetCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣()3️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["3️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar(x: ${1:Int}, y: ${2:Int})")
    XCTAssertEqual(completion.insertTextFormat, .snippet)
  }

  func testFunctionCompletionWithEmptyParensAndExistingTrailingClosure() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: () -> Void) {}

      func test() {
        1️⃣foo2️⃣() {
          doSomethingInTrailingClosure()
        }
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionReplacesWhitespaceOnlyExistingParens() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(                 )3️⃣
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["3️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar(x: , y: )")
  }

  func testFunctionCompletionDoesNotOverwriteMultilineParens() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(

        )
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionWithExistingTrailingClosure() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(body: () -> Void) {}

      func test() {
        1️⃣foobar2️⃣ {}
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { !$0.label.contains("(") })

    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionWithExistingBraceButFunctionDoesNotTakeClosure() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int) {}

      func test() {
        1️⃣foobar2️⃣ {}
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.only)

    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar(x: )")
  }

  func testFunctionCompletionDoesNotTreatCommentOnlyParensAsEmpty() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(/*keep me*/)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionWithExistingOpeningParen() async throws {
    let testClient = try await TestSourceKitLSPClient()
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}

      func test() {
        1️⃣fooba2️⃣(
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("foobar") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "foobar")
  }

  func testFunctionCompletionWithInsertReplaceEditAndExistingParens() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func foobar(x: Int, y: Int) {}
      func foobaz(x: Int, y: Int) {}

      func test() {
        1️⃣foob2️⃣ar()3️⃣
        4️⃣foob5️⃣ar6️⃣(x: 5, y: 3)
      }
      """,
      uri: uri
    )

    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "1️⃣",
      cursor: "2️⃣",
      insertEnd: "2️⃣",
      replaceEnd: "3️⃣",
      matching: { $0.label.contains("foobaz") },
      expectedNewText: "foobaz(x: , y: )"
    )
    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "4️⃣",
      cursor: "5️⃣",
      insertEnd: "5️⃣",
      replaceEnd: "6️⃣",
      matching: { $0.label.contains("foobaz") },
      expectedNewText: "foobaz"
    )
  }

  func testEnumCaseCompletionDoesNotInsertArgumentsIfTheyAlreadyExist() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      enum MyEnum {
        case foobar(x: Int, y: Int)
      }

      func test(value: MyEnum) {
        switch value {
        case .1️⃣foo2️⃣baz3️⃣(x: 5, y: 3):
          break
        case .4️⃣fooba5️⃣z()6️⃣:
          break
        }
      }
      """,
      uri: uri
    )

    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "1️⃣",
      cursor: "2️⃣",
      insertEnd: "2️⃣",
      replaceEnd: "3️⃣",
      matching: { $0.label.contains("foobar") },
      expectedNewText: "foobar"
    )
    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "4️⃣",
      cursor: "5️⃣",
      insertEnd: "5️⃣",
      replaceEnd: "6️⃣",
      matching: { $0.label.contains("foobar") },
      expectedNewText: "foobar(x: , y: )"
    )
  }

  func testInitializerCompletionWithExistingArguments() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Box {
        init(x: Int, y: Int) {}
      }

      func test() {
        let b = 1️⃣Bo2️⃣x3️⃣(x: 5, y: 3)
        let c = 4️⃣Bo5️⃣x6️⃣()7️⃣
      }
      """,
      uri: uri
    )

    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "1️⃣",
      cursor: "2️⃣",
      insertEnd: "2️⃣",
      replaceEnd: "3️⃣",
      matching: { $0.kind == .constructor || $0.label.contains("Box") },
      expectedNewText: "Box"
    )
    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "4️⃣",
      cursor: "5️⃣",
      insertEnd: "5️⃣",
      replaceEnd: "6️⃣",
      matching: { $0.kind == .constructor || $0.label.contains("Box") },
      expectedNewText: "Box"
    )
  }

  func testStaticFactoryCompletionWithExistingAndEmptyParens() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      struct Maker {
        static func build(x: Int, y: Int) -> Maker { Maker() }
      }

      func test() {
        _ = Maker.1️⃣buil2️⃣d3️⃣(x: 5, y: 3)
        _ = Maker.4️⃣buil5️⃣d6️⃣()7️⃣
      }
      """,
      uri: uri
    )

    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "1️⃣",
      cursor: "2️⃣",
      insertEnd: "2️⃣",
      replaceEnd: "3️⃣",
      matching: { $0.label.contains("build") },
      expectedNewText: "build"
    )
    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "4️⃣",
      cursor: "5️⃣",
      insertEnd: "5️⃣",
      replaceEnd: "7️⃣",
      matching: { $0.label.contains("build") },
      expectedNewText: "build(x: , y: )"
    )
  }

  func testMacroCompletionWithExistingAndEmptyParens() async throws {
    let testClient = try await TestSourceKitLSPClient(
      capabilities: insertReplaceEditAndSnippetCapabilities
    )
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      @freestanding(expression)
      macro myMacro(fn: (Int) -> String) = #externalMacro(module: "", type: "")

      func test() {
        _ = #1️⃣myMac2️⃣ro3️⃣(fn: { _ in "x" })
        _ = #4️⃣myMac5️⃣ro()6️⃣
      }
      """,
      uri: uri
    )

    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "1️⃣",
      cursor: "2️⃣",
      insertEnd: "2️⃣",
      replaceEnd: "3️⃣",
      matching: { $0.label.contains("myMacro") },
      expectedNewTextContains: "myMacro"
    )
    try await assertInsertReplaceCompletion(
      testClient: testClient,
      uri: uri,
      positions: positions,
      start: "4️⃣",
      cursor: "5️⃣",
      insertEnd: "5️⃣",
      replaceEnd: "6️⃣",
      matching: { $0.label.contains("myMacro") },
      expectedNewTextContains: "myMacro"
    )
  }

  private func assertInsertReplaceCompletion(
    testClient: TestSourceKitLSPClient,
    uri: DocumentURI,
    positions: DocumentPositions,
    start: String,
    cursor: String,
    insertEnd: String,
    replaceEnd: String,
    matching isMatchingCompletion: (CompletionItem) -> Bool,
    expectedNewText: String? = nil,
    expectedNewTextContains: String? = nil,
    file: StaticString = #filePath,
    line: UInt = #line
  ) async throws {
    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions[cursor])
    )
    let completion = try XCTUnwrap(
      completions.items.first(where: isMatchingCompletion),
      "No matching completion item",
      file: file,
      line: line
    )
    guard case let .insertReplaceEdit(edit)? = completion.textEdit else {
      XCTFail("Expected insert-replace edit", file: file, line: line)
      return
    }
    XCTAssertEqual(edit.insert, positions[start]..<positions[insertEnd], file: file, line: line)
    XCTAssertEqual(edit.replace, positions[start]..<positions[replaceEnd], file: file, line: line)
    if let expectedNewText {
      XCTAssertEqual(edit.newText, expectedNewText, file: file, line: line)
    }
    if let expectedNewTextContains {
      XCTAssertTrue(edit.newText.contains(expectedNewTextContains), file: file, line: line)
    }
  }

  func testCompletionWithExistingArgumentsAndKeywordAsIdentifier() async throws {
    let testClient = try await TestSourceKitLSPClient(capabilities: insertReplaceEditCapabilities)
    let uri = DocumentURI(for: .swift)
    let positions = testClient.openDocument(
      """
      func selfTest(x: Int, y: Int) {}

      func test() {
        1️⃣self2️⃣(x: 5, y: 3)
      }
      """,
      uri: uri
    )

    let completions = try await testClient.send(
      CompletionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
    )
    let completion = try XCTUnwrap(completions.items.first { $0.label.contains("selfTest") })
    guard case let .textEdit(textEdit)? = completion.textEdit else {
      XCTFail("Expected text edit")
      return
    }
    XCTAssertEqual(textEdit.range, positions["1️⃣"]..<positions["2️⃣"])
    XCTAssertEqual(textEdit.newText, "selfTest")
  }
}

private func countFs(_ response: CompletionList) -> Int {
  return response.items.filter { $0.label.hasPrefix("f") }.count
}

private func assertMarkdown(
  documentation: StringOrMarkupContent?,
  expected: String,
  file: StaticString = #filePath,
  line: UInt = #line
) {
  XCTAssertEqual(
    documentation,
    .markupContent(MarkupContent(kind: .markdown, value: expected)),
    file: file,
    line: line
  )
}

fileprivate extension Position {
  func adding(columns: Int) -> Position {
    return Position(line: line, utf16index: utf16index + columns)
  }
}
