Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class Consumer
{
public string Convert(object o)
{
var myClass = new MyClass();
return myClass.ToJson(o);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- Deliberately no direct PackageReference to Newtonsoft.Json: it is only
consumed transitively through the ProjectReference below, mirroring the
"DependentProject" scenario in
https://github.com/razzmatazz/csharp-language-server/issues/318 -->
<ProjectReference Include="..\Project\Project.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Newtonsoft.Json;

public class MyClass
{
public string ToJson(object o)
{
return JsonConvert.SerializeObject(o);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- Central Package Management (CPM): version comes from Directory.Packages.props,
not from this PackageReference item. See
https://github.com/razzmatazz/csharp-language-server/issues/318 -->
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project", "Project\Project.csproj", "{59DABAFE-31BE-47BB-B203-D16E9B90A1DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependentProject", "DependentProject\DependentProject.csproj", "{6A1B2C3D-4E5F-47BB-B203-D16E9B90A1DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{59DABAFE-31BE-47BB-B203-D16E9B90A1DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59DABAFE-31BE-47BB-B203-D16E9B90A1DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59DABAFE-31BE-47BB-B203-D16E9B90A1DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{59DABAFE-31BE-47BB-B203-D16E9B90A1DE}.Release|Any CPU.Build.0 = Release|Any CPU
{6A1B2C3D-4E5F-47BB-B203-D16E9B90A1DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A1B2C3D-4E5F-47BB-B203-D16E9B90A1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A1B2C3D-4E5F-47BB-B203-D16E9B90A1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A1B2C3D-4E5F-47BB-B203-D16E9B90A1DF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
71 changes: 71 additions & 0 deletions tests/CSharpLanguageServer.Tests/InitializationTests.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module CSharpLanguageServer.Tests.InitializationTests

open System
open System.IO

open NUnit.Framework

Expand Down Expand Up @@ -269,6 +270,76 @@ let testPlatformSpecificTfmDoesNotBreakSiblingProjects () =
Assert.That(errors.Length, Is.EqualTo(0), $"expected no errors on Project/Class.cs, got: {errorsStr}")
| _ -> failwith "U2.C1 (full report) was expected"

/// Regression test for https://github.com/razzmatazz/csharp-language-server/issues/318 —
/// projects using NuGet Central Package Management (CPM) via `Directory.Packages.props`
/// (a `<PackageReference>` with no `Version` attribute) reportedly fail to load in the
/// Roslyn MSBuildWorkspace, with a `[Failure]` msbuildWorkspace diagnostic and zero code
/// intelligence for the affected project.
[<Test>]
let testCentralPackageManagementProjectLoadsWithoutMsbuildWorkspaceFailure () =
// Pre-build both projects so that obj/project.assets.json exists for each (restored
// against the centrally-managed package version) before MSBuildWorkspace opens the
// solution. DependentProject has no direct PackageReference of its own — it only
// pulls in Newtonsoft.Json transitively via the ProjectReference to Project,
// mirroring the "DependentProject" symptom reported in the issue.
let prebuildProjects (solutionDir: string) =
for projectName in [ "Project"; "DependentProject" ] do
let projectDir = Path.Combine(solutionDir, projectName)
let exitCode, stdout, stderr = runDotnetBuild projectDir

if exitCode <> 0 then
failwithf
"Pre-build of CPM fixture project '%s' failed (exit %d):\nstdout:\n%s\nstderr:\n%s"
projectName
exitCode
stdout
stderr

use client =
activateFixtureExt "projectWithCentralPackageManagement" defaultClientProfile prebuildProjects id

use classFile = client.Open("Project/Class.cs")
use consumerFile = client.Open("DependentProject/Consumer.cs")

// The bug in #318 manifests as a `[Failure]` msbuildWorkspace.Diagnostics entry
// logged (via window/logMessage) while the solution is being loaded — either for the
// CPM-managed project itself, or for a project that depends on it.
let hasMsbuildWorkspaceFailure =
client.ServerMessageLogContains(fun m -> m.Contains("msbuildWorkspace.Diagnostics") && m.Contains("[Failure]"))

Assert.That(
hasMsbuildWorkspaceFailure,
Is.False,
"Expected the CPM-managed project (and its dependent project) to load without a msbuildWorkspace [Failure] diagnostic"
)

// Sanity-check that code intelligence actually works for the CPM-managed package
// reference: hovering over `JsonConvert` should resolve to the Newtonsoft.Json type.
let hoverParams: HoverParams =
{ TextDocument = { Uri = classFile.Uri }
Position = { Line = 6u; Character = 15u } // `JsonConvert` in `JsonConvert.SerializeObject(o)`
WorkDoneToken = None }

let hover: Hover option = client.Request("textDocument/hover", hoverParams)

match hover with
| Some { Contents = U3.C1 c } -> Assert.That(c.Value, Does.Contain("JsonConvert"))
| _ -> failwith "Expected hover to resolve JsonConvert from the CPM-managed Newtonsoft.Json reference"

// Sanity-check code intelligence for the dependent project too: hovering over
// `MyClass` (defined in the CPM-managed project) should resolve.
let dependentHoverParams: HoverParams =
{ TextDocument = { Uri = consumerFile.Uri }
Position = { Line = 4u; Character = 28u } // `MyClass` in `new MyClass()`
WorkDoneToken = None }

let dependentHover: Hover option =
client.Request("textDocument/hover", dependentHoverParams)

match dependentHover with
| Some { Contents = U3.C1 c } -> Assert.That(c.Value, Does.Contain("MyClass"))
| _ -> failwith "Expected hover to resolve MyClass from the ProjectReference to the CPM-managed project"

[<Test>]
let testMultiTargetWorkspace () =
let clientWorkspaceCaps: WorkspaceClientCapabilities =
Expand Down
1 change: 1 addition & 0 deletions tests/CSharpLanguageServer.Tests/Tooling.fs
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ let prepareTempTestDirFrom (sourceTestDir: DirectoryInfo) : string =
let fileFilter (file: FileInfo) =
file.Name = ".editorconfig"
|| file.Name = "global.json"
|| file.Name = "Directory.Packages.props"
|| file.Extension = ".cs"
|| file.Extension = ".csproj"
|| file.Extension = ".sln"
Expand Down
Loading