Skip to content

Commit

Permalink
determinismtests
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinRansom committed Jun 1, 2023
1 parent 8bed194 commit fe6a6ed
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace FSharp.Compiler.ComponentTests.CompilerOptions

open Xunit
open FSharp.Test
open FSharp.Test.Compiler
open System
open System.IO

module determinism =

let areSame first second =
let load = System.IO.File.ReadAllBytes
if not ((load first) = (load second)) then
raise (new Exception "Pathmap1 and PathMap2 do not match")

let compileSource options compilation =
compilation
|> asLibrary
|> withOptionsString options
|> compile

[<InlineData("--deterministic")>]
[<InlineData("--deterministic+")>]
[<InlineData("--deterministic-")>]
[<InlineData("--deterministic;--debug:full")>]
[<InlineData("--deterministic;--debug:pdbonly")>]
[<InlineData("--deterministic;--debug:portable")>]
[<InlineData("--deterministic;--debug:embedded")>]
[<InlineData("--deterministic+;--debug:embedded")>]
[<InlineData("--deterministic-;--debug:embedded")>]
[<Theory>]
let ``smoketest options`` options =
FSharp """
module Determinism
"""
|> compileSource options
|> shouldSucceed

[<InlineData("--deterministic")>]
[<InlineData("--deterministic-")>]
[<InlineData("--deterministic+")>]
[<Theory>]
let ``Confirm specific version allowed`` options =
FSharp """
module Determinism
[<assembly: System.Reflection.AssemblyVersion("2.3.4.5")>]
do()
"""
|> compileSource options
|> shouldSucceed

[<InlineData("--deterministic-")>]
[<Theory>]
let ``Confirm wildcard version allowed`` options =
FSharp """
module Determinism
[<assembly: System.Reflection.AssemblyVersion("2.3.4.*")>]
do ()
"""
|> compileSource options
|> shouldSucceed

[<InlineData("--deterministic+")>]
[<Theory>]
let ``Confirm wildcard version not allowed`` options =
FSharp """
module Determinism
[<assembly: System.Reflection.AssemblyVersion("2.3.4.*")>]
do ()
"""
|> compileSource options
|> shouldFail
|> withDiagnostics [
(Error 2025, Line 1, Col 1, Line 1, Col 1, "An AssemblyVersionAttribute specified version '2.3.4.*', but this value is a wildcard, and you have requested a deterministic build, these are in conflict.")
]

[<Fact>]
let ``Invalid pathmap value`` () =
FSharp """
module Determinism
"""
|> compileSource @"--pathmap:C:\NoOtherPath;--debug:embedded"
|> shouldFail
|> withDiagnostics [
(Error 2028, Line 0, Col 1, Line 0, Col 1, "Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath'")
]

[<Fact>]
let ``pathmap with Embedded Pdbs`` () =
let thisTestDirectory = getTestOutputDirectory __SOURCE_DIRECTORY__ (getCurrentMethodName()) ""
let pathMap1 =
let compilation =
FsFromPath (Path.Combine(__SOURCE_DIRECTORY__, @"PathMap1\pathmap.fs"))
|> withOutputDirectory thisTestDirectory
compilation
|> withOptionsString $"""--pathmap:{compilation.OutputDirectory}\PathMap1=/src,F:\=/etc;--deterministic;--embed;--debug:embedded"""
|> asExe
|> compile

let pathMap2 =
let compilation =
FsFromPath (Path.Combine(__SOURCE_DIRECTORY__, @"PathMap2\pathmap.fs"))
|> withOutputDirectory thisTestDirectory
compilation
|> withOptionsString $"""--pathmap:{compilation.OutputDirectory}\PathMap2=/src,F:\=/etc;--deterministic;--embed;--debug:embedded"""
|> asExe
|> compile

match pathMap1.Output.OutputPath, pathMap2.Output.OutputPath with
| Some exename1, Some exename2 ->
areSame exename1 exename2
| _ -> raise (new Exception "Pathmap1 and PathMap2 do not match")

[<Fact>]
let ``pathmap with Portable Pdbs`` () =
let thisTestDirectory = getTestOutputDirectory __SOURCE_DIRECTORY__ (getCurrentMethodName()) ""
let pathMap1 =
let compilation =
FsFromPath (Path.Combine(__SOURCE_DIRECTORY__, @"PathMap1\pathmap.fs"))
|> withOutputDirectory thisTestDirectory
compilation
|> withOptionsString $"""--pathmap:{compilation.OutputDirectory}\PathMap1=/src,F:\=/etc;--deterministic;--embed;--debug:portable"""
|> asExe
|> compile

let pathMap2 =
let compilation =
FsFromPath (Path.Combine(__SOURCE_DIRECTORY__, @"PathMap2\pathmap.fs"))
|> withOutputDirectory thisTestDirectory
compilation
|> withOptionsString $"""--pathmap:{compilation.OutputDirectory}\PathMap2=/src,F:\=/etc;--deterministic;--embed;--debug:portable"""
|> asExe
|> compile

match pathMap1.Output.OutputPath, pathMap2.Output.OutputPath with
| Some exename1, Some exename2 ->
areSame exename1 exename2
areSame (Path.ChangeExtension(exename1, "pdb")) (Path.ChangeExtension(exename2, "pdb"))
| _ -> raise (new Exception "Pathmap1 and PathMap2 do not match")

Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ module highentropyva =
[<InlineData(ExecutionPlatform.Arm64, "--highentropyva-")>]
[<InlineData(ExecutionPlatform.Arm, "--highentropyva-")>]
[<Theory>]
let shouldNotGenerateHighEntropyVirtualAddressSpace platform option =
let shouldNotGenerateHighEntropyVirtualAddressSpace platform options =
Fs """printfn "Hello, World!!!" """
|> asExe
|> withPlatform platform
|> withOptions (if String.IsNullOrWhiteSpace option then [] else [option])
|> withOptions (if String.IsNullOrWhiteSpace options then [] else [options])
|> compile
|> shouldSucceed
|> withPeReader(fun rdr -> rdr.PEHeaders.PEHeader.DllCharacteristics)
Expand All @@ -47,11 +47,11 @@ module highentropyva =
[<InlineData(ExecutionPlatform.Arm, "--highentropyva")>]
[<InlineData(ExecutionPlatform.Arm, "--highentropyva+")>]
[<Theory>]
let shouldGenerateHighEntropyVirtualAddressSpace platform option =
let shouldGenerateHighEntropyVirtualAddressSpace platform options =
Fs """printfn "Hello, World!!!" """
|> asExe
|> withPlatform platform
|> withOptions (if String.IsNullOrWhiteSpace option then [] else [option])
|> withOptions (if String.IsNullOrWhiteSpace options then [] else [options])
|> compile
|> shouldSucceed
|> withPeReader(fun rdr -> rdr.PEHeaders.PEHeader.DllCharacteristics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@
<Compile Include="CompilerOptions\fsc\crossoptimize.fs" />
<Compile Include="CompilerOptions\fsc\debug.fs" />
<Compile Include="CompilerOptions\fsc\flaterrors.fs" />
<Compile Include="CompilerOptions\fsc\determinism\determinism.fs" />
<Compile Include="CompilerOptions\fsc\highentropyva.fs" />
<Compile Include="CompilerOptions\fsc\langversion.fs" />
<Compile Include="CompilerOptions\fsc\misc\misc.fs" />
Expand Down
66 changes: 64 additions & 2 deletions tests/FSharp.Test.Utilities/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ open System.Reflection.PortableExecutable
open FSharp.Test.CompilerAssertHelpers
open TestFramework

open System.Runtime.CompilerServices
open System.Runtime.InteropServices


module rec Compiler =
[<AutoOpen>]
type SourceUtilities () =
static member getCurrentMethodName([<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string) = memberName

type BaselineFile =
{
FilePath: string
Expand All @@ -49,6 +57,15 @@ module rec Compiler =
| CS of CSharpCompilationSource
| IL of ILCompilationSource
override this.ToString() = match this with | FS fs -> fs.ToString() | _ -> (sprintf "%A" this )
member this.OutputDirectory =
let toString diOpt =
match diOpt: DirectoryInfo option with
| Some di -> di.FullName
| None -> ""
match this with
| FS fs -> fs.OutputDirectory |> toString
| CS cs -> cs.OutputDirectory |> toString
| _ -> raise (Exception "Not supported for this compilation type")
member this.WithStaticLink(staticLink: bool) = match this with | FS fs -> FS { fs with StaticLink = staticLink } | cu -> cu

type FSharpCompilationSource =
Expand Down Expand Up @@ -191,6 +208,47 @@ module rec Compiler =

let private defaultOptions : string list = []

let normalizePathSeparator (text:string) = text.Replace(@"\", "/")

let normalizeName name =
let invalidPathChars = Array.concat [Path.GetInvalidPathChars(); [| ':'; '\\'; '/'; ' '; '.' |]]
let result = invalidPathChars |> Array.fold(fun (acc:string) (c:char) -> acc.Replace(string(c), "_")) name
result

let getTestOutputDirectory dir testCaseName extraDirectory =
// If the executing assembly has 'artifacts\bin' in it's path then we are operating normally in the CI or dev tests
// Thus the output directory will be in a subdirectory below where we are executing.
// The subdirectory will be relative to the source directory containing the test source file,
// E.g
// When the source code is in:
// $(repo-root)\tests\FSharp.Compiler.ComponentTests\Conformance\PseudoCustomAttributes
// and the test is running in the FSharp.Compiler.ComponentTeststest library
// The output directory will be:
// artifacts\bin\FSharp.Compiler.ComponentTests\$(Flavour)\$(TargetFramework)\tests\FSharp.Compiler.ComponentTests\Conformance\PseudoCustomAttributes
//
// If we can't find anything then we execute in the directory containing the source
//
try
let testlibraryLocation = normalizePathSeparator (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
let pos = testlibraryLocation.IndexOf("artifacts/bin",StringComparison.OrdinalIgnoreCase)
if pos > 0 then
// Running under CI or dev build
let testRoot = Path.Combine(testlibraryLocation.Substring(0, pos), @"tests/")
let testSourceDirectory =
let dirInfo = normalizePathSeparator (Path.GetFullPath(dir))
let testPaths = dirInfo.Replace(testRoot, "").Split('/')
testPaths[0] <- "tests"
Path.Combine(testPaths)
let n = Path.Combine(testlibraryLocation, testSourceDirectory.Trim('/'), normalizeName testCaseName, extraDirectory)
let outputDirectory = new DirectoryInfo(n)
Some outputDirectory
else
raise (new InvalidOperationException($"Failed to find the test output directory:\nTest Library Location: '{testlibraryLocation}'\n Pos: {pos}"))
None

with | e ->
raise (new InvalidOperationException($" '{e.Message}'. Can't get the location of the executing assembly"))

// Not very safe version of reading stuff from file, but we want to fail fast for now if anything goes wrong.
let private getSource (src: TestType) : string =
match src with
Expand Down Expand Up @@ -408,9 +466,13 @@ module rec Compiler =
let withOptions (options: string list) (cUnit: CompilationUnit) : CompilationUnit =
withOptionsHelper options "withOptions is only supported for F#" cUnit

let withOutputDirectory (path: string) (cUnit: CompilationUnit) : CompilationUnit =
let withOptionsString (options: string) (cUnit: CompilationUnit) : CompilationUnit =
let options = if String.IsNullOrWhiteSpace options then [] else (options.Split([|';'|])) |> Array.toList
withOptionsHelper options "withOptionsString is only supported for F#" cUnit

let withOutputDirectory (path: DirectoryInfo option) (cUnit: CompilationUnit) : CompilationUnit =
match cUnit with
| FS fs -> FS { fs with OutputDirectory = Some (DirectoryInfo(path)) }
| FS fs -> FS { fs with OutputDirectory = path }
| _ -> failwith "withOutputDirectory is only supported on F#"

let withBufferWidth (width: int)(cUnit: CompilationUnit) : CompilationUnit =
Expand Down
41 changes: 1 addition & 40 deletions tests/FSharp.Test.Utilities/DirectoryAttribute.fs
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,8 @@ type DirectoryAttribute(dir: string) =
if String.IsNullOrWhiteSpace(dir) then
invalidArg "dir" "Directory cannot be null, empty or whitespace only."

let normalizePathSeparator (text:string) = text.Replace(@"\", "/")

let normalizeName name =
let invalidPathChars = Array.concat [Path.GetInvalidPathChars(); [| ':'; '\\'; '/'; ' '; '.' |]]
let result = invalidPathChars |> Array.fold(fun (acc:string) (c:char) -> acc.Replace(string(c), "_")) name
result

let dirInfo = normalizePathSeparator (Path.GetFullPath(dir))
let outputDirectory methodName extraDirectory =
// If the executing assembly has 'artifacts\bin' in it's path then we are operating normally in the CI or dev tests
// Thus the output directory will be in a subdirectory below where we are executing.
// The subdirectory will be relative to the source directory containing the test source file,
// E.g
// When the source code is in:
// $(repo-root)\tests\FSharp.Compiler.ComponentTests\Conformance\PseudoCustomAttributes
// and the test is running in the FSharp.Compiler.ComponentTeststest library
// The output directory will be:
// artifacts\bin\FSharp.Compiler.ComponentTests\$(Flavour)\$(TargetFramework)\tests\FSharp.Compiler.ComponentTests\Conformance\PseudoCustomAttributes
//
// If we can't find anything then we execute in the directory containing the source
//
try
let testlibraryLocation = normalizePathSeparator (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
let pos = testlibraryLocation.IndexOf("artifacts/bin",StringComparison.OrdinalIgnoreCase)
if pos > 0 then
// Running under CI or dev build
let testRoot = Path.Combine(testlibraryLocation.Substring(0, pos), @"tests/")
let testSourceDirectory =
let testPaths = dirInfo.Replace(testRoot, "").Split('/')
testPaths[0] <- "tests"
Path.Combine(testPaths)
let n = Path.Combine(testlibraryLocation, testSourceDirectory.Trim('/'), normalizeName methodName, extraDirectory)
let outputDirectory = new DirectoryInfo(n)
Some outputDirectory
else
raise (new InvalidOperationException($"Failed to find the test output directory:\nTest Library Location: '{testlibraryLocation}'\n Pos: {pos}"))
None

with | e ->
raise (new InvalidOperationException($" '{e.Message}'. Can't get the location of the executing assembly"))

let outputDirectory methodName extraDirectory = getTestOutputDirectory dir methodName extraDirectory
let mutable baselineSuffix = ""
let mutable includes = Array.empty<string>

Expand Down

This file was deleted.

45 changes: 0 additions & 45 deletions tests/fsharpqa/Source/CompilerOptions/fsc/determinism/env.lst

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit fe6a6ed

Please sign in to comment.