Skip to content

Commit 1092519

Browse files
committed
Refactor how fixtures are acquired and shared
1 parent 3fed529 commit 1092519

File tree

11 files changed

+61
-69
lines changed

11 files changed

+61
-69
lines changed

tests/CSharpLanguageServer.Tests/CodeActionTests.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open CSharpLanguageServer.Tests.Tooling
77

88
[<Test>]
99
let ``code action menu appears on request`` () =
10-
let client = Fixtures.getShared "genericProject"
10+
use client = activateFixture "genericProject"
1111
use classFile = client.Open("Project/Class.cs")
1212

1313
let caParams: CodeActionParams =
@@ -49,7 +49,7 @@ let ``code action menu appears on request`` () =
4949

5050
[<Test>]
5151
let ``extract base class request extracts base class`` () =
52-
let client = Fixtures.getShared "genericProject"
52+
use client = activateFixture "genericProject"
5353
use classFile = client.Open("Project/Class.cs")
5454

5555
let caParams0: CodeActionParams =
@@ -76,7 +76,7 @@ let ``extract base class request extracts base class`` () =
7676

7777
[<Test>]
7878
let ``extract interface code action should extract an interface`` () =
79-
let client = Fixtures.getShared "genericProject"
79+
use client = activateFixture "genericProject"
8080
use classFile = client.Open("Project/Class.cs")
8181

8282
let caArgs: CodeActionParams =

tests/CSharpLanguageServer.Tests/CompletionTests.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open CSharpLanguageServer.Tests.Tooling
77

88
[<Test>]
99
let ``completion works in a .cs file`` () =
10-
let client = Fixtures.getShared "genericProject"
10+
use client = activateFixture "genericProject"
1111

1212
// resolve provider is necessary for lsp client to resolve
1313
// detail and documentation props for a completion item
@@ -97,7 +97,7 @@ let ``completion works in a .cs file`` () =
9797

9898
[<Test>]
9999
let ``completion works for extension methods`` () =
100-
let client = Fixtures.getShared "genericProject"
100+
use client = activateFixture "genericProject"
101101

102102
use classFile =
103103
client.Open("Project/ClassForCompletionTestsWithExtensionMethods.cs")

tests/CSharpLanguageServer.Tests/DefinitionTests.fs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open CSharpLanguageServer.Tests.Tooling
77

88
[<Test>]
99
let testDefinitionWorks () =
10-
let client = Fixtures.getShared "genericProject"
10+
use client = activateFixture "genericProject"
1111
use classFile = client.Open("Project/Class.cs")
1212

1313
let definitionParams0: DefinitionParams =
@@ -44,7 +44,8 @@ let testDefinitionWorks () =
4444

4545
[<Test>]
4646
let testDefinitionWorksInAspNetProject () =
47-
let client = Fixtures.getShared "aspnetProject"
47+
use client = activateFixture "aspnetProject"
48+
4849
use testIndexViewModelCsFile = client.Open("Project/Models/Test/IndexViewModel.cs")
4950
use testControllerCsFile = client.Open("Project/Controllers/TestController.cs")
5051

tests/CSharpLanguageServer.Tests/DiagnosticTests.fs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ open CSharpLanguageServer.Tests.Tooling
1010

1111
[<Test>]
1212
let testPushDiagnosticsWork () =
13-
// 'makeClientFixture' is used here to make sure we get a blank new server/client pair
14-
use client = Fixtures.load "testDiagnosticsWork"
13+
use client = activateFixture "testDiagnosticsWork"
1514

1615
//
1716
// open Class.cs file and wait for diagnostics to be pushed
@@ -61,11 +60,7 @@ let testPushDiagnosticsWork () =
6160

6261
[<Test>]
6362
let testPullDiagnosticsWork () =
64-
use client = Fixtures.load "testDiagnosticsWork"
65-
66-
//
67-
// open Class.cs file and pull diagnostics
68-
//
63+
use client = activateFixture "testDiagnosticsWork"
6964
use classFile = client.Open("Project/Class.cs")
7065

7166
let diagnosticParams: DocumentDiagnosticParams =
@@ -126,7 +121,7 @@ let testPullDiagnosticsWork () =
126121

127122
[<Test>]
128123
let testWorkspaceDiagnosticsWork () =
129-
let client = Fixtures.getShared "testDiagnosticsWork"
124+
use client = activateFixture "testDiagnosticsWork"
130125

131126
let diagnosticParams: WorkspaceDiagnosticParams =
132127
{ WorkDoneToken = None
@@ -158,7 +153,7 @@ let testWorkspaceDiagnosticsWork () =
158153

159154
[<Test>]
160155
let testWorkspaceDiagnosticsWorkWithStreaming () =
161-
let client = Fixtures.getShared "testDiagnosticsWork"
156+
use client = activateFixture "testDiagnosticsWork"
162157

163158
let partialResultToken: ProgressToken = System.Guid.NewGuid() |> string |> U2.C2
164159

tests/CSharpLanguageServer.Tests/DocumentFormattingTests.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ open CSharpLanguageServer.Tests.Tooling
99

1010
[<Test>]
1111
let testEditorConfigFormatting () =
12-
let client = Fixtures.getShared "projectWithEditorConfig"
12+
use client = activateFixture "projectWithEditorConfig"
1313
use classFile = client.Open("Project/Class.cs")
1414

1515
let docFormattingParams0: DocumentFormattingParams =

tests/CSharpLanguageServer.Tests/HoverTests.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open CSharpLanguageServer.Tests.Tooling
77

88
[<Test>]
99
let testHoverWorks () =
10-
let client = Fixtures.getShared "genericProject"
10+
use client = activateFixture "genericProject"
1111
use classFile = client.Open("Project/Class.cs")
1212

1313
//

tests/CSharpLanguageServer.Tests/InitializationTests.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ let assertHoverWorks (client: ClientController) file pos expectedMarkupContent =
2727

2828
[<Test>]
2929
let testServerRegistersCapabilitiesWithTheClient () =
30-
let client = Fixtures.getShared "genericProject"
30+
use client = activateFixture "genericProject"
3131

3232
let serverInfo = client.GetState().ServerInfo.Value
3333
Assert.AreEqual("csharp-ls", serverInfo.Name)
@@ -131,7 +131,7 @@ let testServerRegistersCapabilitiesWithTheClient () =
131131

132132
[<Test>]
133133
let testSlnxSolutionFileWillBeFoundAndLoaded () =
134-
use client = Fixtures.load "projectWithSlnx"
134+
use client = activateFixture "projectWithSlnx"
135135

136136
Assert.IsTrue(client.ServerMessageLogContains(fun m -> m.Contains "1 solution(s) found"))
137137

@@ -147,7 +147,7 @@ let testSlnxSolutionFileWillBeFoundAndLoaded () =
147147

148148
[<Test>]
149149
let testMultiTargetProjectLoads () =
150-
use client = Fixtures.load "multiTargetProject"
150+
use client = activateFixture "multiTargetProject"
151151

152152
Assert.IsTrue(client.ServerMessageLogContains(fun m -> m.Contains "loading project"))
153153

tests/CSharpLanguageServer.Tests/ReferenceTests.fs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open CSharpLanguageServer.Tests.Tooling
77

88
[<Test>]
99
let testReferenceWorks () =
10-
let client = Fixtures.getShared "genericProject"
10+
use client = activateFixture "genericProject"
1111
use classFile = client.Open("Project/Class.cs")
1212

1313
//
@@ -73,10 +73,10 @@ let testReferenceWorks () =
7373

7474
Assert.AreEqual(expectedLocations2, locations2.Value)
7575

76+
7677
[<Test>]
7778
let testReferenceWorksDotnet8 () =
78-
let fixtureName = "testReferenceWorksDotnet8"
79-
use client = Fixtures.load fixtureName
79+
use client = activateFixture "testReferenceWorksDotnet8"
8080
use classFile = client.Open("Project/Class.cs")
8181

8282
//
@@ -142,9 +142,10 @@ let testReferenceWorksDotnet8 () =
142142

143143
Assert.AreEqual(expectedLocations2, locations2.Value)
144144

145+
145146
[<Test>]
146147
let testReferenceWorksToAspNetRazorPageReferencedValue () =
147-
let client = Fixtures.getShared "aspnetProject"
148+
use client = activateFixture "aspnetProject"
148149

149150
use testIndexViewModelCsFile = client.Open("Project/Models/Test/IndexViewModel.cs")
150151
use testControllerCsFile = client.Open("Project/Controllers/TestController.cs")

tests/CSharpLanguageServer.Tests/SemanticTokenTests.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ let decodeSemanticToken legend (semanticToken: SemanticTokens) : DecodedToken[]
6868

6969
[<Test>]
7070
let testSemanticTokens () =
71-
let client = Fixtures.getShared "genericProject"
71+
use client = activateFixture "genericProject"
7272

7373
let semanticTokensOptions =
7474
client.GetState().ServerCapabilities

tests/CSharpLanguageServer.Tests/Tooling.fs

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ open System.Threading.Tasks
1010
open System.Threading
1111
open System.Runtime.InteropServices
1212
open System.Reflection
13+
open System.Text.RegularExpressions
1314

1415
open Newtonsoft.Json.Linq
1516
open Ionide.LanguageServerProtocol.Types
1617
open Ionide.LanguageServerProtocol.Server
17-
open System.Text.RegularExpressions
18+
open NUnit.Framework
1819

1920
let indexJToken (name: string) (jobj: option<JToken>) : option<JToken> =
2021
jobj |> Option.bind (fun p -> p[name] |> Option.ofObj)
@@ -602,7 +603,8 @@ let rec deleteDirectory (path: string) =
602603
Directory.Delete(path)
603604

604605

605-
type FileController(client: MailboxProcessor<ClientEvent>, projectDir: string, filename: string, sharedFixture: bool) =
606+
type FileController
607+
(client: MailboxProcessor<ClientEvent>, projectDir: string, filename: string, fixtureIsReadOnly: bool) =
606608
let mutable fileContents: option<string> = None
607609

608610
member __.FileName = filename
@@ -640,8 +642,8 @@ type FileController(client: MailboxProcessor<ClientEvent>, projectDir: string, f
640642
client.Post(SendServerRpcNotification("textDocument/didOpen", serialize didOpenParams))
641643

642644
member this.DidChange(text: string) =
643-
if sharedFixture then
644-
failwith "cannot invoke FileController.DidChange, this is a shared fixture!"
645+
if fixtureIsReadOnly then
646+
failwith "cannot invoke FileController.DidChange, this is a read-only fixture!"
645647

646648
let didChangeParams: DidChangeTextDocumentParams =
647649
{ TextDocument = { Uri = this.Uri; Version = 2 }
@@ -668,13 +670,19 @@ type FileController(client: MailboxProcessor<ClientEvent>, projectDir: string, f
668670
tes |> Array.rev |> Array.fold applyTextEdit fileContents.Value
669671

670672

671-
type ClientController(client: MailboxProcessor<ClientEvent>, testDataDir: DirectoryInfo, sharedFixture: bool) =
673+
type ClientController(client: MailboxProcessor<ClientEvent>, fixtureName: string, fixtureIsReadOnly: bool) =
672674
let mutable projectDir: string option = None
673675
let mutable solutionLoaded: bool = false
674676

675677
let logMessage m msg =
676678
client.Post(EmitLogMessage(DateTime.Now, (sprintf "ClientActorController.%s" m), msg))
677679

680+
let testAssemblyLocationDir =
681+
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
682+
683+
let sourceTestDataDir =
684+
DirectoryInfo(Path.Combine(testAssemblyLocationDir, "..", "..", "..", "Fixtures", fixtureName))
685+
678686
interface IDisposable with
679687
member __.Dispose() =
680688
if solutionLoaded then
@@ -697,16 +705,23 @@ type ClientController(client: MailboxProcessor<ClientEvent>, testDataDir: Direct
697705
deleteDirectory projectDir
698706
| _ -> ()
699707

708+
member __.FixtureName = fixtureName
709+
member __.FixtureIsReadOnly = fixtureIsReadOnly
700710
member __.ProjectDir: string = projectDir.Value
701711

702-
member this.StartAndWaitForSolutionLoad() =
712+
member this.StartAndWaitForSolutionLoad(clientProfile: ClientProfile) =
713+
if not sourceTestDataDir.Exists then
714+
failwithf "ClientController.Prepare(): no such test data dir \"%s\"" sourceTestDataDir.FullName
715+
716+
client.Post(SetupWithProfile clientProfile)
717+
703718
if solutionLoaded then
704719
failwith "Solution has already been loaded for this ClientController!"
705720

706721
solutionLoaded <- true
707722

708723
let log = logMessage "StartInitializeAndWaitForSolutionLoad"
709-
projectDir <- Some(prepareTempTestDirFrom testDataDir)
724+
projectDir <- Some(prepareTempTestDirFrom sourceTestDataDir)
710725

711726
log "sending ServerStartRequest"
712727
let state = client.PostAndReply(fun rc -> ServerStartRequest(projectDir.Value, rc))
@@ -857,57 +872,37 @@ type ClientController(client: MailboxProcessor<ClientEvent>, testDataDir: Direct
857872
failwithf "request to method \"%s\" has failed with error: %s" method (string errorJToken)
858873

859874
member __.Open(filename: string) : FileController =
860-
let file = new FileController(client, projectDir.Value, filename, sharedFixture)
875+
let file = new FileController(client, projectDir.Value, filename, fixtureIsReadOnly)
861876
file.Open()
862877
file
863878

864879

865-
let setupServerClient (clientProfile: ClientProfile) (testDataDirName: string) (sharedFixture: bool) =
880+
let private activateClient (clientProfile: ClientProfile) (fixtureName: string) (readOnlyFixture: bool) =
866881
let initialState =
867882
{ defaultClientState with
868883
LoggingEnabled = clientProfile.LoggingEnabled }
869884

870885
let clientActor = MailboxProcessor.Start(clientEventLoop initialState)
871-
clientActor.Post(SetupWithProfile clientProfile)
872886

873-
let testAssemblyLocationDir =
874-
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
887+
let client = new ClientController(clientActor, fixtureName, readOnlyFixture)
888+
client.StartAndWaitForSolutionLoad(clientProfile)
889+
client
875890

876-
let actualTestDataDir =
877-
DirectoryInfo(Path.Combine(testAssemblyLocationDir, "..", "..", "..", testDataDirName))
878891

879-
if not actualTestDataDir.Exists then
880-
failwithf "setupServerClient: no such test data dir \"%s\"" actualTestDataDir.FullName
892+
let activeClientsSemaphore =
893+
new SemaphoreSlim(Environment.ProcessorCount, Environment.ProcessorCount)
881894

882-
new ClientController(clientActor, actualTestDataDir, sharedFixture)
895+
896+
let activateFixture fixtureName =
897+
activeClientsSemaphore.Wait()
898+
899+
try
900+
activateClient defaultClientProfile fixtureName false
901+
finally
902+
activeClientsSemaphore.Release() |> ignore
883903

884904

885905
module TextEdit =
886906
let normalizeNewText (s: TextEdit) =
887907
{ s with
888908
NewText = s.NewText.ReplaceLineEndings("\n") }
889-
890-
module Fixtures =
891-
let private sharedFixtures = ConcurrentDictionary<string, Lazy<ClientController>>()
892-
893-
let numCpus = Environment.ProcessorCount
894-
let private setupSemaphore = new SemaphoreSlim(numCpus, numCpus)
895-
896-
let private loadFixture sharedFixture fixtureName =
897-
setupSemaphore.Wait()
898-
899-
try
900-
let projectDir = "Fixtures/" + fixtureName
901-
let client = setupServerClient defaultClientProfile projectDir sharedFixture
902-
client.StartAndWaitForSolutionLoad()
903-
client
904-
finally
905-
setupSemaphore.Release() |> ignore
906-
907-
let load fixtureName = loadFixture false fixtureName
908-
909-
let getShared fixtureName : ClientController =
910-
let lazyClient =
911-
sharedFixtures.GetOrAdd(fixtureName, fun fixtureName -> lazy (loadFixture true fixtureName))
912-
913-
lazyClient.Force()

0 commit comments

Comments
 (0)