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
56 changes: 29 additions & 27 deletions FSharpTests.Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,35 @@
Returns=""
DependsOnTargets="$(CoreCompileDependsOn)"
>
<Fsi Condition=" '%(_CoreCompileResourceInputs.WithCulture)' != 'true' "
CodePage="$(CodePage)"
DefineConstants="$(DefineConstants)"
DisabledWarnings="$(NoWarn)"
DotnetFsiCompilerPath="$(DotnetFsiCompilerPath)"
FsiExec="@(FsiExec)"
LangVersion="$(LangVersion)"
LCID="$(LCID)"
LoadSources="@(LoadSource)"
NoFramework="false"
Optimize="$(Optimize)"
OtherFlags="$(OtherFlags)"
PreferredUILang="$(PreferredUILang)"
ProvideCommandLineArgs="$(ProvideCommandLineArgs)"
UseSources="@(UseSource)"
SkipCompilerExecution="$(SkipCompilerExecution)"
Sources="@(CompileBefore);@(Compile);@(CompileAfter)"
Tailcalls="$(Tailcalls)"
TargetProfile="$(TargetProfile)"
ToolExe="$(FsiToolExe)"
ToolPath="$(FsiToolPath)"
TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
Utf8Output="$(Utf8Output)"
WarningLevel="$(WarningLevel)"
WarningsAsErrors="$(WarningsAsErrors)">
<Output TaskParameter="CommandLineArgs" ItemName="FsiCommandLineArgs" />
</Fsi>
<Fsi Condition=" '%(_CoreCompileResourceInputs.WithCulture)' != 'true' "
CodePage="$(CodePage)"
DefineConstants="$(DefineConstants)"
DisabledWarnings="$(NoWarn)"
DotnetFsiCompilerPath="$(DotnetFsiCompilerPath)"
FsiExec="@(FsiExec)"
LangVersion="$(LangVersion)"
LCID="$(LCID)"
LoadSources="@(LoadSource)"
NoFramework="false"
Optimize="$(Optimize)"
OtherFlags="$(OtherFlags)"
PreferredUILang="$(PreferredUILang)"
ProvideCommandLineArgs="$(ProvideCommandLineArgs)"
UseSources="@(UseSource)"
SkipCompilerExecution="$(SkipCompilerExecution)"
Sources="@(CompileBefore);@(Compile);@(CompileAfter)"
Tailcalls="$(Tailcalls)"
TargetProfile="$(TargetProfile)"
ToolExe="$(FsiToolExe)"
ToolPath="$(FsiToolPath)"
TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
Utf8Output="$(Utf8Output)"
WarningLevel="$(WarningLevel)"
WarningsAsErrors="$(WarningsAsErrors)"
CaptureTextOutput="true" >
<Output TaskParameter="CommandLineArgs" ItemName="FsiCommandLineArgs" />
<Output TaskParameter="TextOutput" ItemName="FsiTextOutput" />
</Fsi>

<ItemGroup>
<_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" />
Expand Down
28 changes: 28 additions & 0 deletions src/FSharp.Build/Fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,34 @@ type public Fsi() as this =

builder

let mutable bufferLimit = None

let textOutput =
lazy System.Collections.Generic.Queue<_>(defaultArg bufferLimit 1024)

override this.LogEventsFromTextOutput(line, msgImportance) =
if this.CaptureTextOutput then
textOutput.Value.Enqueue line

match bufferLimit with
| Some limit when textOutput.Value.Count > limit -> textOutput.Value.Dequeue() |> ignore
| _ -> ()

base.LogEventsFromTextOutput(line, msgImportance)

member _.BufferLimit
with get () = defaultArg bufferLimit 0
and set limit = bufferLimit <- if limit = 0 then None else Some limit

member val CaptureTextOutput = false with get, set

[<Output>]
member this.TextOutput =
if this.CaptureTextOutput then
textOutput.Value |> String.concat Environment.NewLine
else
String.Empty

// --codepage <int>: Specify the codepage to use when opening source files
member _.CodePage
with get () = codePage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ module Tests =
let test3 () =
StaticTest.Test2 // is passing, but probably shouldn't be

printfn "Test Passed"
printf "TEST PASSED OK"
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,15 @@ module ScriptRunner =
let cu = cu |> withDefines defaultDefines
match cu with
| FS fsSource ->
File.Delete("test.ok")
let engine = createEngine (fsSource.Options |> Array.ofList,version)
let res = evalScriptFromDiskInSharedSession engine cu
match res with
| CompilationResult.Failure _ -> res
| CompilationResult.Success s ->
if File.Exists("test.ok") then
| CompilationResult.Success s ->
if engine.GetOutput().Contains "TEST PASSED OK" then
res
else
failwith $"Results looked correct, but 'test.ok' file was not created. Result: %A{s}"
failwith $"Results looked correct, but 'TEST PASSED OK' was not printed. Result: %A{s}"

| _ -> failwith $"Compilation unit other than fsharp is not supported, cannot process %A{cu}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ let aa =
match failures.Value with
| [] ->
stdout.WriteLine "Test Passed"
System.IO.File.WriteAllText("test.ok","ok")
printf "TEST PASSED OK" ;
exit 0
| _ ->
stdout.WriteLine "Test Failed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ let aa =
match failures with
| [] ->
stdout.WriteLine "Test Passed"
System.IO.File.WriteAllText("test.ok","ok")
printf "TEST PASSED OK" ;
exit 0
| _ ->
stdout.WriteLine "Test Failed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5651,7 +5651,7 @@ let aa =
match !failures with
| [] ->
stdout.WriteLine "Test Passed"
System.IO.File.WriteAllText("test.ok","ok")
printf "TEST PASSED OK" ;
exit 0
| _ ->
stdout.WriteLine "Test Failed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -760,10 +760,9 @@ x |> Seq.iter(fun r ->
if found = expected.Length then sawExpectedOutput.Set() |> ignore

let text = "#help"
use output = new RedirectConsoleOutput()
use script = new FSharpScript(quiet = false, langVersion = LangVersion.V47)
let mutable found = 0
output.OutputProduced.Add (fun line -> verifyOutput line)
script.OutputProduced.Add (fun line -> verifyOutput line)
let opt = script.Eval(text) |> getValue
Assert.True(sawExpectedOutput.WaitOne(TimeSpan.FromSeconds(5.0)), sprintf "Expected to see error sentinel value written\nexpected:%A\nactual:%A" expected lines)

Expand Down Expand Up @@ -811,10 +810,9 @@ x |> Seq.iter(fun r ->
if found = expected.Length then sawExpectedOutput.Set() |> ignore

let text = "#help"
use output = new RedirectConsoleOutput()
use script = new FSharpScript(quiet = false, langVersion = LangVersion.Preview)
let mutable found = 0
output.OutputProduced.Add (fun line -> verifyOutput line)
script.OutputProduced.Add (fun line -> verifyOutput line)
let opt = script.Eval(text) |> getValue
Assert.True(sawExpectedOutput.WaitOne(TimeSpan.FromSeconds(5.0)), sprintf "Expected to see error sentinel value written\nexpected:%A\nactual:%A" expected lines)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,19 @@ x

[<Fact>]
member _.``Capture console input``() =
use input = new RedirectConsoleInput()
use script = new FSharpScript()
input.ProvideInput "stdin:1234\r\n"
use script = new FSharpScript(input = "stdin:1234\r\n")
let opt = script.Eval("System.Console.ReadLine()") |> getValue
let value = opt.Value
Assert.Equal(typeof<string>, value.ReflectionType)
Assert.Equal("stdin:1234", downcast value.ReflectionValue)

[<Fact>]
member _.``Capture console output/error``() =
use output = new RedirectConsoleOutput()
use script = new FSharpScript()
use sawOutputSentinel = new ManualResetEvent(false)
use sawErrorSentinel = new ManualResetEvent(false)
output.OutputProduced.Add (fun line -> if line = "stdout:1234" then sawOutputSentinel.Set() |> ignore)
output.ErrorProduced.Add (fun line -> if line = "stderr:5678" then sawErrorSentinel.Set() |> ignore)
script.OutputProduced.Add (fun line -> if line = "stdout:1234" then sawOutputSentinel.Set() |> ignore)
script.ErrorProduced.Add (fun line -> if line = "stderr:5678" then sawErrorSentinel.Set() |> ignore)
script.Eval("printfn \"stdout:1234\"; eprintfn \"stderr:5678\"") |> ignoreValue
Assert.True(sawOutputSentinel.WaitOne(TimeSpan.FromSeconds(5.0)), "Expected to see output sentinel value written")
Assert.True(sawErrorSentinel.WaitOne(TimeSpan.FromSeconds(5.0)), "Expected to see error sentinel value written")
Expand Down Expand Up @@ -305,11 +302,10 @@ printfn ""%A"" result

[<Fact>]
member _.``Eval script with invalid PackageName should fail immediately``() =
use output = new RedirectConsoleOutput()
use script = new FSharpScript(additionalArgs=[| |])
let mutable found = 0
let outp = System.Collections.Generic.List<string>()
output.OutputProduced.Add(
script.OutputProduced.Add(
fun line ->
if line.Contains("error NU1101:") && line.Contains("FSharp.Really.Not.A.Package") then
found <- found + 1
Expand All @@ -321,10 +317,9 @@ printfn ""%A"" result

[<Fact>]
member _.``Eval script with invalid PackageName should fail immediately and resolve one time only``() =
use output = new RedirectConsoleOutput()
use script = new FSharpScript(additionalArgs=[| |])
let mutable foundResolve = 0
output.OutputProduced.Add (fun line -> if line.Contains("error NU1101:") then foundResolve <- foundResolve + 1)
script.OutputProduced.Add (fun line -> if line.Contains("error NU1101:") then foundResolve <- foundResolve + 1)
let result, errors =
script.Eval("""
#r "nuget:FSharp.Really.Not.A.Package"
Expand Down
63 changes: 46 additions & 17 deletions tests/FSharp.Test.Utilities/ScriptHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
namespace FSharp.Test.ScriptHelpers

open System
open System.Collections.Generic
open System.IO
open System.Text
open System.Threading
open FSharp.Compiler
open FSharp.Compiler.Interactive.Shell
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.EditorServices
open FSharp.Test.Utilities
open FSharp.Test

[<RequireQualifiedAccess>]
type LangVersion =
Expand All @@ -25,7 +24,26 @@ type LangVersion =
| Latest
| SupportsMl

type FSharpScript(?additionalArgs: string[], ?quiet: bool, ?langVersion: LangVersion) =
type private EventedTextWriter() =
inherit TextWriter()
let sb = StringBuilder()
let sw = new StringWriter()
let lineWritten = Event<string>()
member _.LineWritten = lineWritten.Publish
override _.Encoding = Encoding.UTF8
override _.Write(c: char) =
if c = '\n' then
let line =
let v = sb.ToString()
if v.EndsWith("\r") then v.Substring(0, v.Length - 1)
else v
sb.Clear() |> ignore
sw.WriteLine line
lineWritten.Trigger(line)
else sb.Append(c) |> ignore
override _.ToString() = sw.ToString()

type FSharpScript(?additionalArgs: string[], ?quiet: bool, ?langVersion: LangVersion, ?input: string) =

let additionalArgs = defaultArg additionalArgs [||]
let quiet = defaultArg quiet true
Expand Down Expand Up @@ -54,13 +72,32 @@ type FSharpScript(?additionalArgs: string[], ?quiet: bool, ?langVersion: LangVer

let argv = Array.append baseArgs additionalArgs

let inReader = new StringReader(defaultArg input "")
let outWriter = new EventedTextWriter()
let errorWriter = new EventedTextWriter()

let previousIn, previousOut, previousError = Console.In, Console.Out, Console.Error

do
Console.SetIn inReader
Console.SetOut outWriter
Console.SetError errorWriter

let fsi = FsiEvaluationSession.Create (config, argv, stdin, stdout, stderr)

member _.ValueBound = fsi.ValueBound

member _.Fsi = fsi

member _.Eval(code: string, ?cancellationToken: CancellationToken, ?desiredCulture: Globalization.CultureInfo) =
member _.OutputProduced = outWriter.LineWritten

member _.ErrorProduced = errorWriter.LineWritten

member _.GetOutput() = string outWriter

member _.GetErrorOutput() = string errorWriter

member this.Eval(code: string, ?cancellationToken: CancellationToken, ?desiredCulture: Globalization.CultureInfo) =
let originalCulture = Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture <- Option.defaultValue Globalization.CultureInfo.InvariantCulture desiredCulture

Expand Down Expand Up @@ -88,7 +125,11 @@ type FSharpScript(?additionalArgs: string[], ?quiet: bool, ?langVersion: LangVer
}

interface IDisposable with
member this.Dispose() = ((this.Fsi) :> IDisposable).Dispose()
member this.Dispose() =
((this.Fsi) :> IDisposable).Dispose()
Console.SetIn previousIn
Console.SetOut previousOut
Console.SetError previousError

[<AutoOpen>]
module TestHelpers =
Expand All @@ -101,15 +142,3 @@ module TestHelpers =
| Error ex -> raise ex

let ignoreValue = getValue >> ignore

let getTempDir () =
let sysTempDir = Path.GetTempPath()
let customTempDirName = Guid.NewGuid().ToString("D")
let fullDirName = Path.Combine(sysTempDir, customTempDirName)
let dirInfo = Directory.CreateDirectory(fullDirName)
{ new Object() with
member _.ToString() = dirInfo.FullName
interface IDisposable with
member _.Dispose() =
dirInfo.Delete(true)
}
Loading
Loading