Make it possible to pass in the project path
This commit is contained in:
parent
b05c2dc0a2
commit
07cdb478a2
1 changed files with 77 additions and 18 deletions
|
|
@ -2,6 +2,7 @@ open System
|
||||||
open System.IO
|
open System.IO
|
||||||
open System.Reflection
|
open System.Reflection
|
||||||
open System.Diagnostics
|
open System.Diagnostics
|
||||||
|
open System.Xml.Linq
|
||||||
|
|
||||||
type MutationCase =
|
type MutationCase =
|
||||||
{ Id: string
|
{ Id: string
|
||||||
|
|
@ -24,13 +25,16 @@ type Command =
|
||||||
|
|
||||||
type Options =
|
type Options =
|
||||||
{ Configuration: string
|
{ Configuration: string
|
||||||
|
ProjectPath: string option
|
||||||
NoBuild: bool
|
NoBuild: bool
|
||||||
Command: Command }
|
Command: Command }
|
||||||
|
|
||||||
let projectPath = "Example.Tests"
|
type ProjectInfo =
|
||||||
let targetFramework = "net10.0"
|
{ RelativeProjectPath: string
|
||||||
let projectDirectory = "example-tests"
|
AbsoluteProjectPath: string
|
||||||
let testProjectPath = Path.Combine(projectDirectory, "Example.Tests", "Example.Tests.fsproj")
|
ProjectDirectory: string
|
||||||
|
AssemblyName: string
|
||||||
|
TargetFramework: string }
|
||||||
|
|
||||||
let fail message =
|
let fail message =
|
||||||
eprintfn "%s" message
|
eprintfn "%s" message
|
||||||
|
|
@ -80,26 +84,81 @@ let makeRelativePath (path: string) =
|
||||||
if Path.IsPathRooted path then Path.GetRelativePath(repoRoot, path) else path
|
if Path.IsPathRooted path then Path.GetRelativePath(repoRoot, path) else path
|
||||||
|
|
||||||
let parseArgs (args: string list) =
|
let parseArgs (args: string list) =
|
||||||
let rec loop configuration noBuild remaining =
|
let rec loop configuration projectPath noBuild remaining =
|
||||||
match remaining with
|
match remaining with
|
||||||
| [] -> { Configuration = configuration; NoBuild = noBuild; Command = Run [] }
|
| [] -> { Configuration = configuration; ProjectPath = projectPath; NoBuild = noBuild; Command = Run [] }
|
||||||
| "--configuration" :: value :: tail -> loop value noBuild tail
|
| "--configuration" :: value :: tail -> loop value projectPath noBuild tail
|
||||||
| "--no-build" :: tail -> loop configuration true tail
|
| "--project" :: value :: tail -> loop configuration (Some value) noBuild tail
|
||||||
| "--list" :: tail when tail.IsEmpty -> { Configuration = configuration; NoBuild = noBuild; Command = List }
|
| "--no-build" :: tail -> loop configuration projectPath true tail
|
||||||
| "--show" :: id :: tail when tail.IsEmpty -> { Configuration = configuration; NoBuild = noBuild; Command = Show id }
|
| "--list" :: tail when tail.IsEmpty -> { Configuration = configuration; ProjectPath = projectPath; NoBuild = noBuild; Command = List }
|
||||||
| "--run" :: tail -> { Configuration = configuration; NoBuild = noBuild; Command = Run tail }
|
| "--show" :: id :: tail when tail.IsEmpty -> { Configuration = configuration; ProjectPath = projectPath; NoBuild = noBuild; Command = Show id }
|
||||||
| value :: tail when not (value.StartsWith "--") -> { Configuration = configuration; NoBuild = noBuild; Command = Run (value :: tail) }
|
| "--run" :: tail -> { Configuration = configuration; ProjectPath = projectPath; NoBuild = noBuild; Command = Run tail }
|
||||||
| _ -> fail "Usage: dotnet fsi verify-coverage-mutants.fsx [--configuration Debug|Release] [--no-build] [--list | --show <id> | --run [id...]]"
|
| value :: tail when not (value.StartsWith "--") -> { Configuration = configuration; ProjectPath = projectPath; NoBuild = noBuild; Command = Run (value :: tail) }
|
||||||
loop "Debug" false args
|
| _ -> fail "Usage: dotnet fsi verify-coverage-mutants.fsx [--project <path/to/project.fsproj>] [--configuration Debug|Release] [--no-build] [--list | --show <id> | --run [id...]]"
|
||||||
|
loop "Debug" None false args
|
||||||
|
|
||||||
let options = parseArgs (fsi.CommandLineArgs |> Array.skip 1 |> Array.toList)
|
let options = parseArgs (fsi.CommandLineArgs |> Array.skip 1 |> Array.toList)
|
||||||
|
|
||||||
|
let ensureWithinRepo (path: string) =
|
||||||
|
let relativePath = Path.GetRelativePath(repoRoot, path)
|
||||||
|
if relativePath = ".." || relativePath.StartsWith($"..{Path.DirectorySeparatorChar}") then
|
||||||
|
fail $"Project path must be inside the repository: {path}"
|
||||||
|
relativePath
|
||||||
|
|
||||||
|
let loadProjectInfo (projectPath: string) =
|
||||||
|
let absoluteProjectPath =
|
||||||
|
if Path.IsPathRooted projectPath then projectPath
|
||||||
|
else Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, projectPath))
|
||||||
|
|
||||||
|
if not (File.Exists absoluteProjectPath) then
|
||||||
|
fail $"Project file not found: {absoluteProjectPath}"
|
||||||
|
|
||||||
|
let relativeProjectPath = ensureWithinRepo absoluteProjectPath
|
||||||
|
let projectDirectory = Path.GetDirectoryName relativeProjectPath
|
||||||
|
let document = XDocument.Load absoluteProjectPath
|
||||||
|
|
||||||
|
let tryGetProperty name =
|
||||||
|
document.Descendants()
|
||||||
|
|> Seq.tryPick (fun element ->
|
||||||
|
if element.Name.LocalName = name then
|
||||||
|
let value = element.Value.Trim()
|
||||||
|
if String.IsNullOrWhiteSpace value then None else Some value
|
||||||
|
else
|
||||||
|
None)
|
||||||
|
|
||||||
|
let targetFramework =
|
||||||
|
match tryGetProperty "TargetFramework" with
|
||||||
|
| Some value -> value
|
||||||
|
| None ->
|
||||||
|
match tryGetProperty "TargetFrameworks" with
|
||||||
|
| Some value ->
|
||||||
|
value.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
|> Array.tryHead
|
||||||
|
|> Option.map _.Trim()
|
||||||
|
|> Option.defaultWith (fun () -> fail $"Could not determine TargetFramework from {relativeProjectPath}")
|
||||||
|
| None -> fail $"Could not determine TargetFramework from {relativeProjectPath}"
|
||||||
|
|
||||||
|
let assemblyName =
|
||||||
|
tryGetProperty "AssemblyName"
|
||||||
|
|> Option.defaultValue (Path.GetFileNameWithoutExtension absoluteProjectPath)
|
||||||
|
|
||||||
|
{ RelativeProjectPath = relativeProjectPath
|
||||||
|
AbsoluteProjectPath = absoluteProjectPath
|
||||||
|
ProjectDirectory = projectDirectory
|
||||||
|
AssemblyName = assemblyName
|
||||||
|
TargetFramework = targetFramework }
|
||||||
|
|
||||||
|
let project =
|
||||||
|
match options.ProjectPath with
|
||||||
|
| Some projectPath -> loadProjectInfo projectPath
|
||||||
|
| None -> fail "Missing required --project <path/to/project.fsproj>."
|
||||||
|
|
||||||
let assemblyPath =
|
let assemblyPath =
|
||||||
Path.Combine(repoRoot, projectDirectory, "Example.Tests", "bin", options.Configuration, targetFramework, "Example.Tests.dll")
|
Path.Combine(repoRoot, project.ProjectDirectory, "bin", options.Configuration, project.TargetFramework, project.AssemblyName + ".dll")
|
||||||
|
|
||||||
let ensureBuilt () =
|
let ensureBuilt () =
|
||||||
if not options.NoBuild then
|
if not options.NoBuild then
|
||||||
let exitCode = runProcess repoRoot "dotnet" [ "build"; testProjectPath; "--configuration"; options.Configuration; "--nologo" ]
|
let exitCode = runProcess repoRoot "dotnet" [ "build"; project.RelativeProjectPath; "--configuration"; options.Configuration; "--nologo" ]
|
||||||
if exitCode <> 0 then fail "dotnet build failed."
|
if exitCode <> 0 then fail "dotnet build failed."
|
||||||
if not (File.Exists assemblyPath) then
|
if not (File.Exists assemblyPath) then
|
||||||
fail $"Compiled test assembly not found at {assemblyPath}."
|
fail $"Compiled test assembly not found at {assemblyPath}."
|
||||||
|
|
@ -209,7 +268,7 @@ let runMutation (mutation: MutationCase) =
|
||||||
|
|
||||||
printfn "==> %s: %s" mutation.Id mutation.TestName
|
printfn "==> %s: %s" mutation.Id mutation.TestName
|
||||||
let buildExitCode =
|
let buildExitCode =
|
||||||
runProcess worktreePath "dotnet" [ "build"; testProjectPath; "--configuration"; options.Configuration; "--nologo" ]
|
runProcess worktreePath "dotnet" [ "build"; project.RelativeProjectPath; "--configuration"; options.Configuration; "--nologo" ]
|
||||||
|
|
||||||
let outcome =
|
let outcome =
|
||||||
if buildExitCode <> 0 then
|
if buildExitCode <> 0 then
|
||||||
|
|
@ -217,7 +276,7 @@ let runMutation (mutation: MutationCase) =
|
||||||
BuildFailed
|
BuildFailed
|
||||||
else
|
else
|
||||||
let testExitCode =
|
let testExitCode =
|
||||||
runProcess worktreePath "dotnet" [ "test"; testProjectPath; "--configuration"; options.Configuration; "--filter"; testFilter mutation; "--no-build"; "--nologo" ]
|
runProcess worktreePath "dotnet" [ "test"; project.RelativeProjectPath; "--configuration"; options.Configuration; "--filter"; testFilter mutation; "--no-build"; "--nologo" ]
|
||||||
|
|
||||||
if testExitCode = 0 then
|
if testExitCode = 0 then
|
||||||
printfn "SURVIVED %s" mutation.Id
|
printfn "SURVIVED %s" mutation.Id
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue