Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make Assertions.withExitCode work #17830

Merged
merged 5 commits into from
Oct 9, 2024
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
4 changes: 2 additions & 2 deletions src/Compiler/Service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ module CompileHelpers =

try
f exiter
0
None
with e ->
stopProcessingRecovery e range0
1
Some e

/// Compile using the given flags. Source files names are resolved via the FileSystem API. The output file must be given by a -o flag.
let compileFromArgs (ctok, argv: string[], legacyReferenceResolver, tcImportsCapture, dynamicAssemblyCreator) =
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/Service/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,12 @@ type public FSharpChecker =
/// Compile using the given flags. Source files names are resolved via the FileSystem API.
/// The output file must be given by a -o flag.
/// The first argument is ignored and can just be "fsc.exe".
/// The method returns the collected diagnostics, and (possibly) a terminating exception.
/// </summary>
///
/// <param name="argv">The command line arguments for the project build.</param>
/// <param name="userOpName">An optional string used for tracing compiler operations associated with this request.</param>
member Compile: argv: string[] * ?userOpName: string -> Async<FSharpDiagnostic[] * int>
member Compile: argv: string[] * ?userOpName: string -> Async<FSharpDiagnostic[] * exn option>

/// <summary>
/// Try to get type check results for a file. This looks up the results of recent type checks of the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace CompilerDirectives

open Xunit
open FSharp.Test.Compiler

module Ifdef =

let ifdefSource = """
[<EntryPoint>]
let main _ =
#if MYDEFINE1
1
#else
2
#endif
"""

[<InlineData("MYDEFINE1", 1)>]
[<InlineData("MYDEFINE", 2)>]
[<Theory>]
let ifdefTest (mydefine, expectedExitCode) =

FSharp ifdefSource
|> withDefines [mydefine]
|> compileExeAndRun
|> withExitCode expectedExitCode


let sourceExtraEndif = """
#if MYDEFINE1
printf "1"
#endif
(**)#endif(**)
0
"""

[<Fact>]
let extraEndif () =

FSharp sourceExtraEndif
|> withDefines ["MYDEFINE1"]
|> asExe
|> compile
|> withDiagnosticMessage "#endif has no matching #if in implementation file"

let sourceUnknownHash = """
module A
#ifxx
#abc
"""

[<Fact>]
let unknownHashDirectiveIsIgnored () =

FSharp sourceUnknownHash
|> compile
|> shouldSucceed
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ else ()
|> compile
|> run
|> shouldSucceed
|> withExitCode 0

[<Fact>]
let ``Respect nowarn 957 for extension method`` () =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ let ``Stackoverflow reproduction`` compilation =
| CompilationResult.Success ({OutputPath = Some dllFile} as s) ->
let fsharpCoreFile = typeof<voption<_>>.Assembly.Location
File.Copy(fsharpCoreFile, Path.Combine(Path.GetDirectoryName(dllFile), Path.GetFileName(fsharpCoreFile)), true)
let exitCode, _stdout, _stderr = CompilerAssert.ExecuteAndReturnResult (dllFile, isFsx=false, deps = s.Dependencies, newProcess=true)
let _exitCode, _stdout, stderr, _exn = CompilerAssert.ExecuteAndReturnResult (dllFile, isFsx=false, deps = s.Dependencies, newProcess=true)

Assert.NotEqual(0,exitCode)
Assert.True(stderr.Contains "stack overflow" || stderr.Contains "StackOverflow")

| _ -> failwith (sprintf "%A" compilationResult)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
</Compile>
<Compile Include="CompilerDirectives\Line.fs" />
<Compile Include="CompilerDirectives\NonStringArgs.fs" />
<Compile Include="CompilerDirectives\Ifdef.fs" />
<Compile Include="Conformance\BasicGrammarElements\AccessibilityAnnotations\Basic\Basic.fs" />
<Compile Include="Conformance\BasicGrammarElements\AccessibilityAnnotations\OnOverridesAndIFaceImpl\OnOverridesAndIFaceImpl.fs" />
<Compile Include="Conformance\BasicGrammarElements\AccessibilityAnnotations\OnTypeMembers\OnTypeMembers.fs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ module CompilationFromCmdlineArgsTests =
yield! methodOptions method
|]

let diagnostics, exitCode = checker.Compile(args) |> Async.RunSynchronously
let diagnostics, exn = checker.Compile(args) |> Async.RunSynchronously

for diag in diagnostics do
printfn "%A" diag

Assert.Equal(exitCode, 0)
Assert.Equal(exn, None)
finally
Environment.CurrentDirectory <- oldWorkDir

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2166,7 +2166,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectSnapshotFromScript(System.String, FSharp.Compiler.Text.ISourceTextNew, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],System.Int32]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],Microsoft.FSharp.Core.FSharpOption`1[System.Exception]]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions],FSharp.Compiler.CodeAnalysis.FSharpProjectOptions] ProjectChecked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2166,7 +2166,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectSnapshotFromScript(System.String, FSharp.Compiler.Text.ISourceTextNew, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],System.Int32]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],Microsoft.FSharp.Core.FSharpOption`1[System.Exception]]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions],FSharp.Compiler.CodeAnalysis.FSharpProjectOptions] ProjectChecked
Expand Down
52 changes: 26 additions & 26 deletions tests/FSharp.Test.Utilities/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,13 @@ module rec Compiler =
Message: string
SubCategory: string }

// This type is used either for the output of the compiler (typically in CompilationResult coming from 'compile')
// or for the output of the code generated by the compiler (in CompilationResult coming from 'run')
type ExecutionOutput =
{ ExitCode: int
{ ExitCode: int option
StdOut: string
StdErr: string }
StdErr: string
Exn: exn option }

type RunOutput =
| EvalOutput of Result<FsiValue option, exn>
Expand Down Expand Up @@ -699,7 +702,7 @@ module rec Compiler =
let private compileFSharpCompilation compilation ignoreWarnings (cUnit: CompilationUnit) : CompilationResult =

use redirect = new RedirectConsole()
let ((err: FSharpDiagnostic[], rc: int, outputFilePath: string), deps) =
let ((err: FSharpDiagnostic[], exn, outputFilePath: string), deps) =
CompilerAssert.CompileRaw(compilation, ignoreWarnings)

// Create and stash the console output
Expand All @@ -711,7 +714,7 @@ module rec Compiler =
Adjust = 0
PerFileErrors = diagnostics
Diagnostics = diagnostics |> List.map snd
Output = Some (RunOutput.ExecutionOutput { ExitCode = rc; StdOut = redirect.Output(); StdErr = redirect.ErrorOutput() })
Output = Some (RunOutput.ExecutionOutput { ExitCode = None; StdOut = redirect.Output(); StdErr = redirect.ErrorOutput(); Exn = exn })
Compilation = cUnit
}

Expand Down Expand Up @@ -978,14 +981,13 @@ module rec Compiler =
| SourceCodeFileKind.Fsx _ -> true
| _ -> false
| _ -> false
let exitCode, output, errors = CompilerAssert.ExecuteAndReturnResult (p, isFsx, s.Dependencies, false)
let exitCode, output, errors, exn = CompilerAssert.ExecuteAndReturnResult (p, isFsx, s.Dependencies, false)
printfn "---------output-------\n%s\n-------" output
printfn "---------errors-------\n%s\n-------" errors
let executionResult = { s with Output = Some (ExecutionOutput { ExitCode = exitCode; StdOut = output; StdErr = errors }) }
if exitCode = 0 then
CompilationResult.Success executionResult
else
CompilationResult.Failure executionResult
let executionResult = { s with Output = Some (ExecutionOutput { ExitCode = exitCode; StdOut = output; StdErr = errors; Exn = exn }) }
match exn with
| None -> CompilationResult.Success executionResult
| Some _ -> CompilationResult.Failure executionResult

let compileAndRun = compile >> run

Expand Down Expand Up @@ -1080,27 +1082,25 @@ module rec Compiler =
opts.ToArray()
let errors, stdOut = CompilerAssert.RunScriptWithOptionsAndReturnResult options source

let executionOutputwithStdOut: RunOutput option =
ExecutionOutput { StdOut = stdOut; ExitCode = 0; StdErr = "" }
|> Some
let result =
let mkResult output =
{ OutputPath = None
Dependencies = []
Adjust = 0
Diagnostics = []
PerFileErrors= []
Output = executionOutputwithStdOut
Output = Some output
Compilation = cUnit }

if errors.Count > 0 then
let output = ExecutionOutput {
ExitCode = -1
StdOut = String.Empty
StdErr = ((errors |> String.concat "\n").Replace("\r\n","\n")) }
CompilationResult.Failure { result with Output = Some output }

if errors.Count = 0 then
let output =
ExecutionOutput { ExitCode = None; StdOut = stdOut; StdErr = ""; Exn = None }
CompilationResult.Success (mkResult output)
else
CompilationResult.Success result

let err = (errors |> String.concat "\n").Replace("\r\n","\n")
let output =
ExecutionOutput {ExitCode = None; StdOut = String.Empty; StdErr = err; Exn = None }
CompilationResult.Failure (mkResult output)

finally
disposals
|> Seq.iter (fun x -> x.Dispose())
Expand Down Expand Up @@ -1190,7 +1190,7 @@ Actual:
| Some p ->
match ILChecker.verifyILAndReturnActual [] p expected with
| true, _, _ -> result
| false, errorMsg, _actualIL -> CompilationResult.Failure( {s with Output = Some (ExecutionOutput { StdOut = errorMsg; ExitCode = 0; StdErr = "" })} )
| false, errorMsg, _actualIL -> CompilationResult.Failure( {s with Output = Some (ExecutionOutput {ExitCode = None; StdOut = errorMsg; StdErr = ""; Exn = None })} )

| CompilationResult.Failure f -> failwith $"Result should be \"Success\" in order to get IL. Failure: {Environment.NewLine}{f}"

Expand Down Expand Up @@ -1706,7 +1706,7 @@ Actual:
| None -> failwith "Execution output is missing, cannot check exit code."
| Some o ->
match o with
| ExecutionOutput e -> Assert.Equal(expectedExitCode, e.ExitCode)
| ExecutionOutput {ExitCode = Some exitCode} -> Assert.Equal(expectedExitCode, exitCode)
| _ -> failwith "Cannot check exit code on this run result."
result

Expand Down
Loading
Loading