Skip to content

Commit 5232e6e

Browse files
committed
tests: add tests for extract interface
1 parent 2ecef15 commit 5232e6e

File tree

12 files changed

+267
-143
lines changed

12 files changed

+267
-143
lines changed

Directory.Packages.props

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
<ItemGroup>
1313
<PackageVersion Include="Argu" Version="6.2.5" />
1414
<PackageVersion Include="Castle.Core" Version="5.2.1" />
15-
<PackageVersion Include="coverlet.collector" Version="3.0.3" />
15+
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
1616
<PackageVersion Include="DotNet.ReproducibleBuilds" Version="1.2.25" />
1717
<PackageVersion Include="FSharp.Control.AsyncSeq" Version="3.2.1" />
18+
<PackageVersion Include="FsUnit" Version="7.1.1" />
1819
<PackageVersion Include="ICSharpCode.Decompiler" Version="9.1.0.7988" />
1920
<PackageVersion Include="Ionide.KeepAChangelog.Tasks" Version="0.1.8" />
2021
<PackageVersion Include="Ionide.LanguageServerProtocol" Version="0.7.0" />
@@ -31,7 +32,7 @@
3132
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
3233
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.9" />
3334
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.9" />
34-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
35+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
3536
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
3637
<PackageVersion Include="NUnit" Version="3.14.0" />
3738
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />

src/CSharpLanguageServer/CSharpLanguageServer.fsproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
<ItemGroup>
2424
<Compile Include="Logging.fs" />
2525
<Compile Include="Util.fs" />
26-
<Compile Include="ReflectedTypes.fs" />
2726
<Compile Include="Conversions.fs" />
2827
<Compile Include="Types.fs" />
2928
<Compile Include="FormatUtil.fs" />

src/CSharpLanguageServer/RoslynHelpers.fs

Lines changed: 93 additions & 83 deletions
Large diffs are not rendered by default.

src/CSharpLanguageServer/Util.fs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ module CSharpLanguageServer.Util
22

33
open System
44
open System.Runtime.InteropServices
5+
open System.Threading.Tasks
56
open System.IO
6-
open Microsoft.Build.Utilities
7+
open System.Reflection
78

89
let nonNull name (value: 'T when 'T: null) : 'T =
910
if Object.ReferenceEquals(value, null) then
@@ -75,6 +76,16 @@ let formatInColumns (data: list<list<string>>) : string =
7576
|> String.concat Environment.NewLine
7677

7778

79+
[<AutoOpen>]
80+
module TaskExtensions =
81+
type Task with
82+
static member private fromResultMI =
83+
typeof<Task>.GetMethod("FromResult")
84+
|> nonNull (sprintf "%s.FromResult()" (string typeof<Task>))
85+
86+
static member fromResult(taskType: Type, resultValue: obj | null) =
87+
Task.fromResultMI.MakeGenericMethod([| taskType |]).Invoke(null, [| resultValue |])
88+
7889
module Seq =
7990
let inline tryMaxBy (projection: 'T -> 'U) (source: 'T seq) : 'T option =
8091
if isNull source || Seq.isEmpty source then
@@ -96,11 +107,3 @@ module Map =
96107
let union map1 map2 =
97108
Map.fold (fun acc key value -> Map.add key value acc) map1 map2
98109

99-
type TaskOfType (taskType: Type) =
100-
static let fromResultMethod =
101-
typeof<Task>.GetMethod("FromResult")
102-
|> nonNull (sprintf "%s.FromResult()" (string typeof<Task>))
103-
let typedFromResultMethod = fromResultMethod.MakeGenericMethod([| taskType |])
104-
105-
member __.FromResult(resultValue: obj | null) =
106-
typedFromResultMethod.Invoke(null, [| resultValue |])
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module AssemblyInfo
2+
3+
open NUnit.Framework
4+
5+
[<assembly: Parallelizable(ParallelScope.All)>]
6+
do ()

tests/CSharpLanguageServer.Tests/CSharpLanguageServer.Tests.fsproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11+
<Compile Include="AssemblyInfo.fs" />
1112
<Compile Include="Tooling.fs" />
1213
<Compile Include="CodeActionTests.fs" />
1314
<Compile Include="DiagnosticTests.fs" />
@@ -24,10 +25,14 @@
2425
</ItemGroup>
2526

2627
<ItemGroup>
28+
<PackageReference Include="FsUnit" />
2729
<PackageReference Include="Microsoft.NET.Test.Sdk" />
2830
<PackageReference Include="NUnit" />
2931
<PackageReference Include="NUnit3TestAdapter" />
30-
<PackageReference Include="coverlet.collector" />
32+
<PackageReference Include="coverlet.collector">
33+
<PrivateAssets>all</PrivateAssets>
34+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
35+
</PackageReference>
3136
</ItemGroup>
3237

3338
<ItemGroup>
Lines changed: 126 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,131 @@
1-
module CSharpLanguageServer.Tests.CodeActionTests
1+
namespace CSharpLanguageServer.Tests
22

33
open NUnit.Framework
44
open Ionide.LanguageServerProtocol.Types
5-
65
open CSharpLanguageServer.Tests.Tooling
76

8-
[<TestCase>]
9-
let testCodeActionOnMethodNameWorks () =
10-
use client =
11-
setupServerClient defaultClientProfile "TestData/testCodeActionOnMethodNameWorks"
12-
13-
client.StartAndWaitForSolutionLoad()
14-
15-
use classFile = client.Open("Project/Class.cs")
16-
17-
let caParams0: CodeActionParams =
18-
{ TextDocument = { Uri = classFile.Uri }
19-
Range =
20-
{ Start = { Line = 2u; Character = 16u }
21-
End = { Line = 2u; Character = 16u } }
22-
Context =
23-
{ Diagnostics = [||]
24-
Only = None
25-
TriggerKind = None }
26-
WorkDoneToken = None
27-
PartialResultToken = None }
28-
29-
let caResult0: TextDocumentCodeActionResult option =
30-
client.Request("textDocument/codeAction", caParams0)
31-
32-
Assert.IsTrue(caResult0.IsSome)
33-
34-
match caResult0 with
35-
| Some [| U2.C2 x |] ->
36-
Assert.AreEqual("Extract base class...", x.Title)
37-
Assert.AreEqual(None, x.Kind)
38-
Assert.AreEqual(None, x.Diagnostics)
39-
Assert.AreEqual(None, x.Disabled)
40-
Assert.IsTrue(x.Edit.IsSome)
41-
42-
| _ -> failwith "Some [| U2.C1 x |] was expected"
7+
[<TestFixture>]
8+
type CodeActionTests() =
9+
10+
static let mutable client: ClientController =
11+
setupServerClient defaultClientProfile "TestData/testCodeActions"
12+
13+
[<OneTimeSetUp>]
14+
member _.Setup() = client.StartAndWaitForSolutionLoad()
15+
16+
[<Test>]
17+
member _.``code action menu appears on request``() =
18+
use classFile = client.Open("Project/Class.cs")
19+
20+
let caParams: CodeActionParams =
21+
{ TextDocument = { Uri = classFile.Uri }
22+
Range =
23+
{ Start = { Line = 1u; Character = 0u }
24+
End = { Line = 1u; Character = 0u } }
25+
Context =
26+
{ Diagnostics = [||]
27+
Only = None
28+
TriggerKind = None }
29+
WorkDoneToken = None
30+
PartialResultToken = None }
31+
32+
let caResult: TextDocumentCodeActionResult option =
33+
client.Request("textDocument/codeAction", caParams)
34+
35+
let assertCodeActionHasTitle (ca: CodeAction, title: string) =
36+
Assert.AreEqual(title, ca.Title)
37+
Assert.AreEqual(None, ca.Kind)
38+
Assert.AreEqual(None, ca.Diagnostics)
39+
Assert.AreEqual(None, ca.Disabled)
40+
Assert.IsTrue(ca.Edit.IsSome)
41+
42+
match caResult with
43+
| Some [| U2.C2 generateOverrides
44+
U2.C2 extractInterface
45+
U2.C2 generateConstructor
46+
U2.C2 extractBaseClass
47+
U2.C2 addDebuggerDisplay |] ->
48+
assertCodeActionHasTitle (generateOverrides, "Generate overrides...")
49+
assertCodeActionHasTitle (extractInterface, "Extract interface...")
50+
assertCodeActionHasTitle (generateConstructor, "Generate constructor 'Class()'")
51+
assertCodeActionHasTitle (extractBaseClass, "Extract base class...")
52+
assertCodeActionHasTitle (addDebuggerDisplay, "Add 'DebuggerDisplay' attribute")
53+
54+
| _ -> failwith "Not all code actions were matched as expected"
55+
56+
[<Test>]
57+
member _.``extract base class request extracts base class``() =
58+
use classFile = client.Open("Project/Class.cs")
59+
60+
let caParams0: CodeActionParams =
61+
{ TextDocument = { Uri = classFile.Uri }
62+
Range =
63+
{ Start = { Line = 2u; Character = 16u }
64+
End = { Line = 2u; Character = 16u } }
65+
Context =
66+
{ Diagnostics = [||]
67+
Only = None
68+
TriggerKind = None }
69+
WorkDoneToken = None
70+
PartialResultToken = None }
71+
72+
let caResult: TextDocumentCodeActionResult option =
73+
client.Request("textDocument/codeAction", caParams0)
74+
75+
match caResult with
76+
| Some [| U2.C2 x |] -> Assert.AreEqual("Extract base class...", x.Title)
77+
// TODO: match extract base class edit structure
78+
79+
| _ -> failwith "Some [| U2.C2 x |] was expected"
80+
81+
[<Test>]
82+
member _.``extract interface code action should extract an interface``() =
83+
use classFile = client.Open("Project/Class.cs")
84+
85+
let caArgs: CodeActionParams =
86+
{ TextDocument = { Uri = classFile.Uri }
87+
Range =
88+
{ Start = { Line = 0u; Character = 0u }
89+
End = { Line = 0u; Character = 0u } }
90+
Context =
91+
{ Diagnostics = [||]
92+
Only = Some [| "refactor.extract.interface" |]
93+
TriggerKind = Some CodeActionTriggerKind.Invoked }
94+
WorkDoneToken = None
95+
PartialResultToken = None }
96+
97+
let caOptions: TextDocumentCodeActionResult option =
98+
match client.Request("textDocument/codeAction", caArgs) with
99+
| Some opts -> opts
100+
| None -> failwith "Expected code actions"
101+
102+
let codeAction =
103+
match caOptions |> Option.bind (Array.tryItem 1) with
104+
| Some(U2.C2 ca) ->
105+
Assert.AreEqual("Extract interface...", ca.Title)
106+
ca
107+
| _ -> failwith "Extract interface action not found"
108+
109+
let expectedImplementInterfaceEdits =
110+
{ Range =
111+
{ Start = { Line = 0u; Character = 11u }
112+
End = { Line = 0u; Character = 11u } }
113+
NewText = " : IClass" }
114+
115+
let expectedCreateInterfaceEdits =
116+
{ Range =
117+
{ Start = { Line = 0u; Character = 0u }
118+
End = { Line = 0u; Character = 0u } }
119+
NewText = "internal interface IClass\n{\n void Method(string arg);\n}" }
120+
121+
match codeAction.Edit with
122+
| Some { DocumentChanges = Some [| U4.C1 create; U4.C1 implement |] } ->
123+
match create.Edits, implement.Edits with
124+
| [| U2.C1 createEdits |], [| U2.C1 implementEdits |] ->
125+
Assert.AreEqual(expectedCreateInterfaceEdits, createEdits |> TextEdit.normalizeNewText)
126+
127+
Assert.AreEqual(expectedImplementInterfaceEdits, implementEdits |> TextEdit.normalizeNewText)
128+
129+
| _ -> failwith "Expected exactly one U2.C1 edit in both create/implement"
130+
131+
| _ -> failwith "Unexpected edit structure"

tests/CSharpLanguageServer.Tests/DocumentFormattingTests.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ let testEditorConfigFormatting () =
3333
| Some tes ->
3434
let expectedClassContents =
3535
File.ReadAllText(Path.Combine(client.ProjectDir, "Project", "ExpectedFormatting.cs.txt"))
36+
|> Text.normalizeLineEndings
37+
let actualClassContents =
38+
classFile.GetFileContentsWithTextEditsApplied(tes)
39+
|> Text.normalizeLineEndings
3640

37-
Assert.AreEqual(expectedClassContents, classFile.GetFileContentsWithTextEditsApplied(tes))
41+
Assert.AreEqual(expectedClassContents, actualClassContents)
3842
| None -> failwith "Some TextEdit's were expected"

tests/CSharpLanguageServer.Tests/HoverTests.fs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ let testHoverWorks () =
2929
match hover.Contents with
3030
| U3.C1 c ->
3131
Assert.AreEqual(MarkupKind.Markdown, c.Kind)
32-
Assert.AreEqual("```csharp\nvoid Class.Method(string arg)\n```", c.Value)
32+
let actualHoverContents = c.Value |> Text.normalizeLineEndings
33+
Assert.AreEqual("```csharp\nvoid Class.Method(string arg)\n```", actualHoverContents)
3334
| _ -> failwith "C1 was expected"
3435

3536
Assert.IsTrue(hover.Range.IsNone)
@@ -55,12 +56,8 @@ let testHoverWorks () =
5556
Assert.AreEqual(MarkupKind.Markdown, c.Kind)
5657

5758
Assert.AreEqual(
58-
"""```csharp
59-
string
60-
```
61-
62-
Represents text as a sequence of UTF-16 code units.""",
63-
c.Value.ReplaceLineEndings()
59+
"```csharp\nstring\n```\n\nRepresents text as a sequence of UTF-16 code units.",
60+
c.Value |> Text.normalizeLineEndings
6461
)
6562
| _ -> failwith "C1 was expected"
6663

0 commit comments

Comments
 (0)