|
1 | 1 | Imports System |
| 2 | +Imports System.Diagnostics |
2 | 3 | Imports System.IO |
3 | 4 | Imports System.Threading |
4 | 5 | Imports System.Threading.Tasks |
@@ -178,6 +179,57 @@ Namespace VbNet.LanguageServer.Tests.Integration |
178 | 179 | End If |
179 | 180 | End Function |
180 | 181 |
|
| 182 | + <Fact> |
| 183 | + Public Async Function GetDefinitionAsync_SdkVbConsoleWithCSharpNetStandardReference_NavigatesToCSharpSource() As Task |
| 184 | + Dim fixture = CreateSdkVbConsoleCSharpReferenceFixture() |
| 185 | + |
| 186 | + Try |
| 187 | + Await RestoreProjectAsync(fixture.SolutionPath).ConfigureAwait(False) |
| 188 | + |
| 189 | + Dim loaded = Await _workspaceManager.LoadSolutionAsync(fixture.SolutionPath).ConfigureAwait(False) |
| 190 | + Assert.True(loaded) |
| 191 | + |
| 192 | + Dim programUri = New Uri(fixture.ProgramPath).ToString() |
| 193 | + Dim text = Await File.ReadAllTextAsync(fixture.ProgramPath).ConfigureAwait(False) |
| 194 | + |
| 195 | + _documentManager.HandleDidOpen(New DidOpenTextDocumentParams With { |
| 196 | + .TextDocument = New TextDocumentItem With { |
| 197 | + .Uri = programUri, |
| 198 | + .LanguageId = "vb", |
| 199 | + .Version = 1, |
| 200 | + .Text = text |
| 201 | + } |
| 202 | + }) |
| 203 | + |
| 204 | + Dim lines = text.Split(ControlChars.Lf) |
| 205 | + Dim lineIndex = Array.FindIndex(lines, Function(line) line.Contains("Utils.GetMessage", StringComparison.Ordinal)) |
| 206 | + Assert.True(lineIndex >= 0) |
| 207 | + |
| 208 | + Dim getMessageIndex = lines(lineIndex).IndexOf("GetMessage", StringComparison.Ordinal) |
| 209 | + Dim request = New DefinitionParams With { |
| 210 | + .TextDocument = New TextDocumentIdentifier With {.Uri = programUri}, |
| 211 | + .Position = New Position With {.Line = lineIndex, .Character = getMessageIndex + 2} |
| 212 | + } |
| 213 | + |
| 214 | + Dim result = Await _definitionService.GetDefinitionAsync(request, CancellationToken.None).ConfigureAwait(False) |
| 215 | + |
| 216 | + Assert.NotEmpty(result) |
| 217 | + Dim sourceLocation = result.FirstOrDefault(Function(location) Uri.UnescapeDataString(New Uri(location.Uri).LocalPath).EndsWith("Utils.cs", StringComparison.OrdinalIgnoreCase)) |
| 218 | + Assert.NotNull(sourceLocation) |
| 219 | + |
| 220 | + Dim utilsLines = (Await File.ReadAllTextAsync(fixture.UtilsPath).ConfigureAwait(False)).Split(ControlChars.Lf) |
| 221 | + Dim expectedLine = Array.FindIndex(utilsLines, Function(line) line.Contains("GetMessage()", StringComparison.Ordinal)) |
| 222 | + Dim expectedCharacter = utilsLines(expectedLine).IndexOf("GetMessage", StringComparison.Ordinal) |
| 223 | + |
| 224 | + Assert.Equal(expectedLine, sourceLocation.Range.Start.Line) |
| 225 | + Assert.Equal(expectedCharacter, sourceLocation.Range.Start.Character) |
| 226 | + Finally |
| 227 | + If Directory.Exists(fixture.RootPath) Then |
| 228 | + Directory.Delete(fixture.RootPath, recursive:=True) |
| 229 | + End If |
| 230 | + End Try |
| 231 | + End Function |
| 232 | + |
181 | 233 | <Fact> |
182 | 234 | Public Async Function GetDefinitionAsync_ReturnsValidRange() As Task |
183 | 235 | Dim projectPath = Path.Combine(TestProjectsRoot, "SmallProject", "SmallProject.vbproj") |
@@ -224,6 +276,134 @@ Namespace VbNet.LanguageServer.Tests.Integration |
224 | 276 | Assert.True(location.Range.End.Line >= location.Range.Start.Line) |
225 | 277 | End If |
226 | 278 | End Function |
| 279 | + |
| 280 | + Private Shared Function CreateSdkVbConsoleCSharpReferenceFixture() As SdkVbConsoleCSharpReferenceFixture |
| 281 | + Dim root = Path.Combine(Path.GetTempPath(), "vbnet-lsp-tests", Guid.NewGuid().ToString("N")) |
| 282 | + |
| 283 | + Try |
| 284 | + Dim consoleDir = Path.Combine(root, "Console", "CoreConsole2") |
| 285 | + Dim libDir = Path.Combine(root, "lib", "MyLib") |
| 286 | + Directory.CreateDirectory(consoleDir) |
| 287 | + Directory.CreateDirectory(libDir) |
| 288 | + |
| 289 | + Dim programPath = Path.Combine(consoleDir, "Program.vb") |
| 290 | + Dim utilsPath = Path.Combine(libDir, "Utils.cs") |
| 291 | + Dim solutionPath = Path.Combine(consoleDir, "CoreConsole2.slnx") |
| 292 | + |
| 293 | + File.WriteAllText( |
| 294 | + programPath, |
| 295 | + "Imports System" & Environment.NewLine & |
| 296 | + "Imports MyLib" & Environment.NewLine & |
| 297 | + Environment.NewLine & |
| 298 | + "Module Program" & Environment.NewLine & |
| 299 | + " Sub Main(args As String())" & Environment.NewLine & |
| 300 | + " Console.WriteLine(Utils.GetMessage())" & Environment.NewLine & |
| 301 | + " End Sub" & Environment.NewLine & |
| 302 | + "End Module") |
| 303 | + File.WriteAllText( |
| 304 | + Path.Combine(consoleDir, "CoreConsole2.vbproj"), |
| 305 | + "<Project Sdk=""Microsoft.NET.Sdk"">" & Environment.NewLine & |
| 306 | + " <PropertyGroup>" & Environment.NewLine & |
| 307 | + " <OutputType>Exe</OutputType>" & Environment.NewLine & |
| 308 | + " <RootNamespace>CoreConsole2</RootNamespace>" & Environment.NewLine & |
| 309 | + " <TargetFramework>net10.0</TargetFramework>" & Environment.NewLine & |
| 310 | + " </PropertyGroup>" & Environment.NewLine & |
| 311 | + " <ItemGroup>" & Environment.NewLine & |
| 312 | + " <ProjectReference Include=""..\..\lib\MyLib\MyLib.csproj"" />" & Environment.NewLine & |
| 313 | + " </ItemGroup>" & Environment.NewLine & |
| 314 | + "</Project>") |
| 315 | + File.WriteAllText( |
| 316 | + utilsPath, |
| 317 | + "using System;" & Environment.NewLine & |
| 318 | + Environment.NewLine & |
| 319 | + "namespace MyLib" & Environment.NewLine & |
| 320 | + "{" & Environment.NewLine & |
| 321 | + " public static class Utils" & Environment.NewLine & |
| 322 | + " {" & Environment.NewLine & |
| 323 | + " public static string GetMessage()" & Environment.NewLine & |
| 324 | + " {" & Environment.NewLine & |
| 325 | + " return ""Hello from MyLib (netstandard)"";" & Environment.NewLine & |
| 326 | + " }" & Environment.NewLine & |
| 327 | + " }" & Environment.NewLine & |
| 328 | + "}") |
| 329 | + File.WriteAllText( |
| 330 | + Path.Combine(libDir, "MyLib.csproj"), |
| 331 | + "<Project Sdk=""Microsoft.NET.Sdk"">" & Environment.NewLine & |
| 332 | + " <PropertyGroup>" & Environment.NewLine & |
| 333 | + " <TargetFramework>netstandard2.0</TargetFramework>" & Environment.NewLine & |
| 334 | + " <GenerateAssemblyInfo>false</GenerateAssemblyInfo>" & Environment.NewLine & |
| 335 | + " <RootNamespace>MyLib</RootNamespace>" & Environment.NewLine & |
| 336 | + " <AssemblyName>MyLib</AssemblyName>" & Environment.NewLine & |
| 337 | + " </PropertyGroup>" & Environment.NewLine & |
| 338 | + "</Project>") |
| 339 | + File.WriteAllText( |
| 340 | + solutionPath, |
| 341 | + "<Solution>" & Environment.NewLine & |
| 342 | + " <Project Path=""..\..\lib\MyLib\MyLib.csproj"" />" & Environment.NewLine & |
| 343 | + " <Project Path=""CoreConsole2.vbproj"" />" & Environment.NewLine & |
| 344 | + "</Solution>") |
| 345 | + |
| 346 | + Return New SdkVbConsoleCSharpReferenceFixture With { |
| 347 | + .RootPath = root, |
| 348 | + .ProgramPath = programPath, |
| 349 | + .UtilsPath = utilsPath, |
| 350 | + .SolutionPath = solutionPath |
| 351 | + } |
| 352 | + Catch |
| 353 | + If Directory.Exists(root) Then |
| 354 | + Directory.Delete(root, recursive:=True) |
| 355 | + End If |
| 356 | + |
| 357 | + Throw |
| 358 | + End Try |
| 359 | + End Function |
| 360 | + |
| 361 | + Private NotInheritable Class SdkVbConsoleCSharpReferenceFixture |
| 362 | + Public Property RootPath As String |
| 363 | + Public Property ProgramPath As String |
| 364 | + Public Property UtilsPath As String |
| 365 | + Public Property SolutionPath As String |
| 366 | + End Class |
| 367 | + |
| 368 | + Private Shared Async Function RestoreProjectAsync(projectOrSolutionPath As String) As Task |
| 369 | + Dim startInfo As New ProcessStartInfo With { |
| 370 | + .FileName = "dotnet", |
| 371 | + .RedirectStandardError = True, |
| 372 | + .RedirectStandardOutput = True, |
| 373 | + .UseShellExecute = False |
| 374 | + } |
| 375 | + startInfo.ArgumentList.Add("restore") |
| 376 | + startInfo.ArgumentList.Add(projectOrSolutionPath) |
| 377 | + |
| 378 | + Using restoreProcess = Process.Start(startInfo) |
| 379 | + Assert.NotNull(restoreProcess) |
| 380 | + |
| 381 | + Dim standardOutput = restoreProcess.StandardOutput.ReadToEndAsync() |
| 382 | + Dim standardError = restoreProcess.StandardError.ReadToEndAsync() |
| 383 | + |
| 384 | + Using timeout As New CancellationTokenSource(TimeSpan.FromMinutes(2)) |
| 385 | + Try |
| 386 | + Await restoreProcess.WaitForExitAsync(timeout.Token).ConfigureAwait(False) |
| 387 | + Catch ex As OperationCanceledException |
| 388 | + Try |
| 389 | + If Not restoreProcess.HasExited Then |
| 390 | + restoreProcess.Kill(entireProcessTree:=True) |
| 391 | + End If |
| 392 | + Catch |
| 393 | + End Try |
| 394 | + |
| 395 | + Assert.True(False, "dotnet restore timed out for test fixture: " & projectOrSolutionPath) |
| 396 | + End Try |
| 397 | + End Using |
| 398 | + |
| 399 | + Dim output = Await standardOutput.ConfigureAwait(False) |
| 400 | + Dim [error] = Await standardError.ConfigureAwait(False) |
| 401 | + |
| 402 | + Assert.True( |
| 403 | + restoreProcess.ExitCode = 0, |
| 404 | + "dotnet restore failed for test fixture:" & Environment.NewLine & output & Environment.NewLine & [error]) |
| 405 | + End Using |
| 406 | + End Function |
227 | 407 | End Class |
228 | 408 |
|
229 | 409 | End Namespace |
0 commit comments