@@ -401,6 +401,80 @@ final class SwiftSourceKitPluginTests: XCTestCase {
401
401
XCTAssertEqual ( result3. items. count, 1 )
402
402
}
403
403
404
+ func testEditBounds( ) async throws {
405
+ try await SkipUnless . sourcekitdSupportsPlugin ( )
406
+ let sourcekitd = try await getSourceKitD ( )
407
+ let path = scratchFilePath ( )
408
+ _ = try await sourcekitd. openDocument (
409
+ path,
410
+ contents: " " ,
411
+ compilerArguments: [ path]
412
+ )
413
+
414
+ let typeWithMethod = """
415
+ struct S {
416
+ static func foo() -> Int {}
417
+ }
418
+
419
+ """
420
+ var fullText = typeWithMethod
421
+
422
+ try await sourcekitd. editDocument ( path, fromOffset: 0 , length: 0 , newContents: typeWithMethod)
423
+
424
+ let completion = """
425
+ S.
426
+ """
427
+ fullText += completion
428
+
429
+ try await sourcekitd. editDocument ( path, fromOffset: typeWithMethod. utf8. count, length: 0 , newContents: completion)
430
+
431
+ func testCompletion( file: StaticString = #filePath, line: UInt = #line) async throws {
432
+ let result = try await sourcekitd. completeOpen (
433
+ path: path,
434
+ position: Position ( line: 3 , utf16index: 2 ) ,
435
+ filter: " foo " ,
436
+ flags: [ ]
437
+ )
438
+ XCTAssertGreaterThan ( result. unfilteredResultCount, 1 , file: file, line: line)
439
+ XCTAssertEqual ( result. items. count, 1 , file: file, line: line)
440
+ }
441
+ try await testCompletion ( )
442
+
443
+ // Bogus edits are ignored (negative offsets crash SourceKit itself so we don't test them here).
444
+ await assertThrowsError (
445
+ try await sourcekitd. editDocument ( path, fromOffset: 0 , length: 99999 , newContents: " " )
446
+ )
447
+ await assertThrowsError (
448
+ try await sourcekitd. editDocument ( path, fromOffset: 99999 , length: 1 , newContents: " " )
449
+ )
450
+ await assertThrowsError (
451
+ try await sourcekitd. editDocument ( path, fromOffset: 99999 , length: 0 , newContents: " unrelated " )
452
+ )
453
+ // SourceKit doesn't throw an error for a no-op edit.
454
+ try await sourcekitd. editDocument ( path, fromOffset: 99999 , length: 0 , newContents: " " )
455
+
456
+ try await sourcekitd. editDocument ( path, fromOffset: 0 , length: 0 , newContents: " " )
457
+ try await sourcekitd. editDocument ( path, fromOffset: fullText. utf8. count, length: 0 , newContents: " " )
458
+
459
+ try await testCompletion ( )
460
+
461
+ let badCompletion = """
462
+ X.
463
+ """
464
+ fullText = fullText. dropLast ( 2 ) + badCompletion
465
+
466
+ try await sourcekitd. editDocument ( path, fromOffset: fullText. utf8. count - 2 , length: 2 , newContents: badCompletion)
467
+
468
+ let result = try await sourcekitd. completeOpen (
469
+ path: path,
470
+ position: Position ( line: 3 , utf16index: 2 ) ,
471
+ filter: " foo " ,
472
+ flags: [ ]
473
+ )
474
+ XCTAssertEqual ( result. unfilteredResultCount, 0 )
475
+ XCTAssertEqual ( result. items. count, 0 )
476
+ }
477
+
404
478
func testDocumentation( ) async throws {
405
479
try await SkipUnless . sourcekitdSupportsPlugin ( )
406
480
let sourcekitd = try await getSourceKitD ( )
0 commit comments