|
12 | 12 |
|
13 | 13 | import LSPTestSupport
|
14 | 14 | import LanguageServerProtocol
|
15 |
| -import SKCore |
| 15 | +@_spi(Testing) import SKCore |
16 | 16 | import SKTestSupport
|
17 | 17 | import SemanticIndex
|
18 | 18 | import SourceKitLSP
|
19 | 19 | import XCTest
|
20 | 20 |
|
| 21 | +import class TSCBasic.Process |
| 22 | + |
21 | 23 | final class BackgroundIndexingTests: XCTestCase {
|
22 | 24 | func testBackgroundIndexingOfSingleFile() async throws {
|
23 | 25 | let project = try await SwiftPMTestProject(
|
@@ -1107,4 +1109,126 @@ final class BackgroundIndexingTests: XCTestCase {
|
1107 | 1109 | )
|
1108 | 1110 | XCTAssertEqual(response, .locations([try project.location(from: "1️⃣", to: "1️⃣", in: "LibB.swift")]))
|
1109 | 1111 | }
|
| 1112 | + |
| 1113 | + func testUpdatePackageDependency() async throws { |
| 1114 | + try SkipUnless.longTestsEnabled() |
| 1115 | + |
| 1116 | + let dependencyProject = try await SwiftPMDependencyProject(files: [ |
| 1117 | + "Sources/MyDependency/Dependency.swift": """ |
| 1118 | + /// Do something v1.0.0 |
| 1119 | + public func doSomething() {} |
| 1120 | + """ |
| 1121 | + ]) |
| 1122 | + let dependencySwiftURL = dependencyProject.packageDirectory |
| 1123 | + .appendingPathComponent("Sources") |
| 1124 | + .appendingPathComponent("MyDependency") |
| 1125 | + .appendingPathComponent("Dependency.swift") |
| 1126 | + defer { dependencyProject.keepAlive() } |
| 1127 | + |
| 1128 | + let project = try await SwiftPMTestProject( |
| 1129 | + files: [ |
| 1130 | + "Test.swift": """ |
| 1131 | + import MyDependency |
| 1132 | +
|
| 1133 | + func test() { |
| 1134 | + 1️⃣doSomething() |
| 1135 | + } |
| 1136 | + """ |
| 1137 | + ], |
| 1138 | + manifest: """ |
| 1139 | + let package = Package( |
| 1140 | + name: "MyLibrary", |
| 1141 | + dependencies: [.package(url: "\(dependencyProject.packageDirectory)", from: "1.0.0")], |
| 1142 | + targets: [ |
| 1143 | + .target( |
| 1144 | + name: "MyLibrary", |
| 1145 | + dependencies: [.product(name: "MyDependency", package: "MyDependency")] |
| 1146 | + ) |
| 1147 | + ] |
| 1148 | + ) |
| 1149 | + """, |
| 1150 | + enableBackgroundIndexing: true |
| 1151 | + ) |
| 1152 | + let packageResolvedURL = project.scratchDirectory.appendingPathComponent("Package.resolved") |
| 1153 | + |
| 1154 | + let originalPackageResolvedContents = try String(contentsOf: packageResolvedURL) |
| 1155 | + |
| 1156 | + // First check our setup to see that we get the expected hover response before changing the dependency project. |
| 1157 | + let (uri, positions) = try project.openDocument("Test.swift") |
| 1158 | + let hoverBeforeUpdate = try await project.testClient.send( |
| 1159 | + HoverRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"]) |
| 1160 | + ) |
| 1161 | + XCTAssert( |
| 1162 | + hoverBeforeUpdate?.contents.markupContent?.value.contains("Do something v1.0.0") ?? false, |
| 1163 | + "Did not contain expected string: \(String(describing: hoverBeforeUpdate))" |
| 1164 | + ) |
| 1165 | + |
| 1166 | + // Just committing a new version of the dependency shouldn't change anything because we didn't update the package |
| 1167 | + // dependencies. |
| 1168 | + try """ |
| 1169 | + /// Do something v1.1.0 |
| 1170 | + public func doSomething() {} |
| 1171 | + """.write(to: dependencySwiftURL, atomically: true, encoding: .utf8) |
| 1172 | + try await dependencyProject.tag(changedFiles: [dependencySwiftURL], version: "1.1.0") |
| 1173 | + |
| 1174 | + let hoverAfterNewVersionCommit = try await project.testClient.send( |
| 1175 | + HoverRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"]) |
| 1176 | + ) |
| 1177 | + XCTAssert( |
| 1178 | + hoverAfterNewVersionCommit?.contents.markupContent?.value.contains("Do something v1.0.0") ?? false, |
| 1179 | + "Did not contain expected string: \(String(describing: hoverBeforeUpdate))" |
| 1180 | + ) |
| 1181 | + |
| 1182 | + // Updating Package.swift causes a package reload but should not cause dependencies to be updated. |
| 1183 | + project.testClient.send( |
| 1184 | + DidChangeWatchedFilesNotification(changes: [ |
| 1185 | + FileEvent(uri: DocumentURI(project.scratchDirectory.appendingPathComponent("Package.resolved")), type: .changed) |
| 1186 | + ]) |
| 1187 | + ) |
| 1188 | + _ = try await project.testClient.send(PollIndexRequest()) |
| 1189 | + XCTAssertEqual(try String(contentsOf: packageResolvedURL), originalPackageResolvedContents) |
| 1190 | + |
| 1191 | + // Simulate a package update which goes as follows: |
| 1192 | + // - The user runs `swift package update` |
| 1193 | + // - This updates `Package.resolved`, which we watch |
| 1194 | + // - We reload the package, which updates `Dependency.swift` in `.index-build/checkouts`, which we also watch. |
| 1195 | + try await Process.run( |
| 1196 | + arguments: [ |
| 1197 | + unwrap(ToolchainRegistry.forTesting.default?.swift?.pathString), |
| 1198 | + "package", "update", |
| 1199 | + "--package-path", project.scratchDirectory.path, |
| 1200 | + ], |
| 1201 | + workingDirectory: nil |
| 1202 | + ) |
| 1203 | + XCTAssertNotEqual(try String(contentsOf: packageResolvedURL), originalPackageResolvedContents) |
| 1204 | + project.testClient.send( |
| 1205 | + DidChangeWatchedFilesNotification(changes: [ |
| 1206 | + FileEvent(uri: DocumentURI(project.scratchDirectory.appendingPathComponent("Package.resolved")), type: .changed) |
| 1207 | + ]) |
| 1208 | + ) |
| 1209 | + _ = try await project.testClient.send(PollIndexRequest()) |
| 1210 | + project.testClient.send( |
| 1211 | + DidChangeWatchedFilesNotification( |
| 1212 | + changes: FileManager.default.findFiles(named: "Dependency.swift", in: project.scratchDirectory).map { |
| 1213 | + FileEvent(uri: DocumentURI($0), type: .changed) |
| 1214 | + } |
| 1215 | + ) |
| 1216 | + ) |
| 1217 | + |
| 1218 | + try await repeatUntilExpectedResult { |
| 1219 | + let hoverAfterPackageUpdate = try await project.testClient.send( |
| 1220 | + HoverRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"]) |
| 1221 | + ) |
| 1222 | + return hoverAfterPackageUpdate?.contents.markupContent?.value.contains("Do something v1.1.0") ?? false |
| 1223 | + } |
| 1224 | + } |
| 1225 | +} |
| 1226 | + |
| 1227 | +extension HoverResponseContents { |
| 1228 | + var markupContent: MarkupContent? { |
| 1229 | + switch self { |
| 1230 | + case .markupContent(let markupContent): return markupContent |
| 1231 | + default: return nil |
| 1232 | + } |
| 1233 | + } |
1110 | 1234 | }
|
0 commit comments