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

Move deterministic tests from fsharpqa to componenttests #15283

Merged
merged 3 commits into from
Jun 2, 2023
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
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