@@ -3,8 +3,16 @@ namespace FScript.TypeProvider.Tests
33open System
44open System.Diagnostics
55open System.IO
6+ open System.Text
67open NUnit.Framework
78
9+ type ProcessRunResult =
10+ { ExitCode: int
11+ Stdout: string
12+ Stderr: string
13+ Duration: TimeSpan
14+ TimedOut: bool }
15+
816[<TestFixture>]
917type TypeProviderIntegrationTests () =
1018 let findRepoRoot () =
@@ -21,7 +29,14 @@ type TypeProviderIntegrationTests () =
2129
2230 loop TestContext.CurrentContext.TestDirectory
2331
24- let runProcess ( workingDirectory : string ) ( fileName : string ) ( arguments : string ) =
32+ let runProcess
33+ ( workingDirectory : string )
34+ ( fileName : string )
35+ ( arguments : string )
36+ ( timeout : TimeSpan )
37+ : ProcessRunResult =
38+ let stdout = StringBuilder()
39+ let stderr = StringBuilder()
2540 let startInfo =
2641 ProcessStartInfo(
2742 FileName = fileName,
@@ -31,42 +46,97 @@ type TypeProviderIntegrationTests () =
3146 RedirectStandardError = true ,
3247 UseShellExecute = false )
3348
49+ use outputClosed = new System.Threading.ManualResetEventSlim( false )
50+ use errorClosed = new System.Threading.ManualResetEventSlim( false )
51+
3452 use proc = new Process( StartInfo = startInfo)
53+ proc.OutputDataReceived.Add( fun args ->
54+ match args.Data with
55+ | null -> outputClosed.Set()
56+ | value -> stdout.AppendLine( value) |> ignore)
57+ proc.ErrorDataReceived.Add( fun args ->
58+ match args.Data with
59+ | null -> errorClosed.Set()
60+ | value -> stderr.AppendLine( value) |> ignore)
61+
62+ let startedAt = DateTimeOffset.UtcNow
3563 proc.Start() |> ignore
36- let stdout = proc.StandardOutput.ReadToEnd()
37- let stderr = proc.StandardError.ReadToEnd()
38- proc.WaitForExit()
39- proc.ExitCode, stdout, stderr
64+ proc.BeginOutputReadLine()
65+ proc.BeginErrorReadLine()
66+
67+ let completed = proc.WaitForExit( int timeout.TotalMilliseconds)
68+ if not completed then
69+ try
70+ proc.Kill( true )
71+ with _ -> ()
72+ proc.WaitForExit()
73+
74+ outputClosed.Wait( TimeSpan.FromSeconds( 5.0 )) |> ignore
75+ errorClosed.Wait( TimeSpan.FromSeconds( 5.0 )) |> ignore
76+ let endedAt = DateTimeOffset.UtcNow
77+
78+ { ExitCode = proc.ExitCode
79+ Stdout = stdout.ToString()
80+ Stderr = stderr.ToString()
81+ Duration = endedAt - startedAt
82+ TimedOut = not completed }
83+
84+ let formatResult ( commandLine : string ) ( result : ProcessRunResult ) =
85+ let output = result.Stdout + " \n " + result.Stderr
86+ let trimmedOutput =
87+ if output.Length > 12000 then
88+ output.Substring( 0 , 12000 ) + " \n ...[truncated]..."
89+ else
90+ output
91+ $" Command: {commandLine}\n ExitCode: {result.ExitCode}\n TimedOut: {result.TimedOut}\n Duration: {result.Duration}\n Output:\n {trimmedOutput}"
92+
93+ let buildCommand fixturePath =
94+ $" build \" {fixturePath}\" -c Release --disable-build-servers /p:UseSharedCompilation=false /nodeReuse:false"
4095
4196 [<Test>]
4297 member _. ``type provider builds valid script fixture`` () =
4398 let repoRoot = findRepoRoot ()
4499 let fixturePath = Path.Combine( repoRoot, " tests" , " FScript.TypeProvider.Tests.Fixtures.Valid" )
45- let exitCode , stdout , stderr = runProcess repoRoot " dotnet" $" build \" {fixturePath}\" -c Release"
46- let output = stdout + " \n " + stderr
47- Assert.That( exitCode, Is.EqualTo( 0 ), $" Expected build success. Output:\n {output}" )
100+ let command = buildCommand fixturePath
101+ let commandLine = " dotnet " + command
102+ let result = runProcess repoRoot " dotnet" command ( TimeSpan.FromSeconds( 120.0 ))
103+ let detail = formatResult commandLine result
104+ Assert.That( result.TimedOut, Is.False, $" Build command timed out.\n {detail}" )
105+ Assert.That( result.ExitCode, Is.EqualTo( 0 ), $" Expected build success.\n {detail}" )
48106
49107 [<Test>]
50108 member _. ``type provider fails compilation on script type error`` () =
51109 let repoRoot = findRepoRoot ()
52110 let fixturePath = Path.Combine( repoRoot, " tests" , " FScript.TypeProvider.Tests.Fixtures.Invalid" )
53- let exitCode , stdout , stderr = runProcess repoRoot " dotnet" $" build \" {fixturePath}\" -c Release"
54- let output = stdout + " \n " + stderr
55- Assert.That( exitCode, Is.Not.EqualTo( 0 ), " Expected build failure for invalid script." )
56- Assert.That( output, Does.Contain( " Failed to type-check FScript" ))
111+ let command = buildCommand fixturePath
112+ let commandLine = " dotnet " + command
113+ let result = runProcess repoRoot " dotnet" command ( TimeSpan.FromSeconds( 120.0 ))
114+ let output = result.Stdout + " \n " + result.Stderr
115+ let detail = formatResult commandLine result
116+ Assert.That( result.TimedOut, Is.False, $" Build command timed out.\n {detail}" )
117+ Assert.That( result.ExitCode, Is.Not.EqualTo( 0 ), $" Expected build failure for invalid script.\n {detail}" )
118+ Assert.That( output, Does.Contain( " Failed to type-check FScript" ), detail)
57119
58120 [<Test>]
59121 member _. ``type provider fails unsupported exported signature`` () =
60122 let repoRoot = findRepoRoot ()
61123 let fixturePath = Path.Combine( repoRoot, " tests" , " FScript.TypeProvider.Tests.Fixtures.Unsupported" )
62- let exitCode , stdout , stderr = runProcess repoRoot " dotnet" $" build \" {fixturePath}\" -c Release"
63- let output = stdout + " \n " + stderr
64- Assert.That( exitCode, Is.Not.EqualTo( 0 ), " Expected build failure for unsupported signature." )
65- Assert.That( output, Does.Contain( " not supported in exported signatures" ))
124+ let command = buildCommand fixturePath
125+ let commandLine = " dotnet " + command
126+ let result = runProcess repoRoot " dotnet" command ( TimeSpan.FromSeconds( 120.0 ))
127+ let output = result.Stdout + " \n " + result.Stderr
128+ let detail = formatResult commandLine result
129+ Assert.That( result.TimedOut, Is.False, $" Build command timed out.\n {detail}" )
130+ Assert.That( result.ExitCode, Is.Not.EqualTo( 0 ), $" Expected build failure for unsupported signature.\n {detail}" )
131+ Assert.That( output, Does.Contain( " not supported in exported signatures" ), detail)
66132
67133 [<Test>]
68134 member _. ``runtime resolver override can replace implementation and mismatch is rejected`` () =
69135 let repoRoot = findRepoRoot ()
70136 let fixturePath = Path.Combine( repoRoot, " tests" , " FScript.TypeProvider.Tests.Fixtures.RuntimeOverride" )
71- let exitCode , stdout , stderr = runProcess repoRoot " dotnet" $" run --project \" {fixturePath}\" -c Release"
72- Assert.That( exitCode, Is.EqualTo( 0 ), $" Expected runtime fixture success.\n Stdout:\n {stdout}\n Stderr:\n {stderr}" )
137+ let command = $" run --project \" {fixturePath}\" -c Release --disable-build-servers"
138+ let commandLine = " dotnet " + command
139+ let result = runProcess repoRoot " dotnet" command ( TimeSpan.FromSeconds( 180.0 ))
140+ let detail = formatResult commandLine result
141+ Assert.That( result.TimedOut, Is.False, $" Runtime command timed out.\n {detail}" )
142+ Assert.That( result.ExitCode, Is.EqualTo( 0 ), $" Expected runtime fixture success.\n {detail}" )
0 commit comments