Compare commits
10 commits
627e7f76a5
...
c13b257083
| Author | SHA1 | Date | |
|---|---|---|---|
| c13b257083 | |||
| cf8f914df0 | |||
| 9ca9bfd687 | |||
| de5843a783 | |||
| 9ff53f1803 | |||
| 500b3f0d8c | |||
| 294b2f85a9 | |||
| ae246d3f36 | |||
| 63d0219e9e | |||
| 5a521e7bfc |
12 changed files with 123 additions and 56 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -211,3 +211,6 @@ FakesAssemblies/
|
|||
|
||||
# Codex
|
||||
.codex
|
||||
|
||||
# Nix
|
||||
result
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
namespace Example
|
||||
|
||||
module Calculator =
|
||||
let addOne value = value + 1
|
||||
|
||||
let absoluteDifference left right =
|
||||
if left >= right then left - right else right - left
|
||||
|
||||
let isLeapYear year =
|
||||
year % 4 = 0 && (year % 100 <> 0 || year % 400 = 0)
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
namespace Example.Tests
|
||||
|
||||
open Example
|
||||
open Mutannot
|
||||
open Xunit
|
||||
|
||||
type CalculatorTests() =
|
||||
[<Fact>]
|
||||
[<MutationCase("""
|
||||
diff --git a/Example.Tests/Calculator.fs b/Example.Tests/Calculator.fs
|
||||
index cfcce3b..39be7f3 100644
|
||||
--- a/Example.Tests/Calculator.fs
|
||||
+++ b/Example.Tests/Calculator.fs
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace Example
|
||||
|
||||
module Calculator =
|
||||
- let addOne value = value + 1
|
||||
+ let addOne value = value - 1
|
||||
|
||||
let absoluteDifference left right =
|
||||
if left >= right then left - right else right - left
|
||||
|
||||
member _.AddOne_increments() =
|
||||
Assert.Equal(42, Calculator.addOne 41)
|
||||
""")>]
|
||||
member _.AddOne_increments() = Assert.Equal(42, Calculator.addOne 41)
|
||||
4
Example/Calculator.fs
Normal file
4
Example/Calculator.fs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
namespace Example
|
||||
|
||||
module Calculator =
|
||||
let addOne value = value + 1
|
||||
21
Example/CalculatorTests.fs
Normal file
21
Example/CalculatorTests.fs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
namespace Example
|
||||
|
||||
open Example
|
||||
open Mutannot
|
||||
open Xunit
|
||||
|
||||
type CalculatorTests() =
|
||||
[<Fact>]
|
||||
[<MutationCase("""
|
||||
diff --git a/Example/Calculator.fs b/Example/Calculator.fs
|
||||
index 6f0c515..030e391 100644
|
||||
--- a/Example/Calculator.fs
|
||||
+++ b/Example/Calculator.fs
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Example
|
||||
|
||||
module Calculator =
|
||||
- let addOne value = value + 1
|
||||
+ let addOne value = value - 1
|
||||
""")>]
|
||||
member _.AddOne_increments() = Assert.Equal(42, Calculator.addOne 41)
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Argu" Version="6.2.5" />
|
||||
<PackageReference Include="Fli" Version="1.1000.0" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ open System.IO
|
|||
open System.Reflection
|
||||
open System.Runtime.InteropServices
|
||||
open Fli
|
||||
open Argu
|
||||
|
||||
type MutationCase = { TestName: string; Patch: string }
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ let runTest projectPath testName =
|
|||
Output(new StreamWriter(Console.OpenStandardOutput()))
|
||||
}
|
||||
|> Command.execute
|
||||
|> ignore
|
||||
|> Output.toExitCode
|
||||
|
||||
let getAssemblyPath projectPath =
|
||||
cli {
|
||||
|
|
@ -79,7 +80,7 @@ let getMetadataLoadContext (assemblyPath: string) =
|
|||
|
||||
new MetadataLoadContext(pathAssemblyResolver, typeof<obj>.Assembly.GetName().Name)
|
||||
|
||||
let unindented (s: string) =
|
||||
let unindentPatch (s: string) =
|
||||
let lines = s.Split([| "\r\n"; "\n" |], StringSplitOptions.None)
|
||||
|
||||
let indexOfFirstNonEmptyLine =
|
||||
|
|
@ -114,26 +115,81 @@ let getMutationCases projectPath =
|
|||
| "Mutannot.MutationCaseAttribute" ->
|
||||
Some
|
||||
{ TestName = $"{m.DeclaringType.FullName}.{m.Name}"
|
||||
Patch = attr.ConstructorArguments[0].Value :?> string |> unindented }
|
||||
Patch = attr.ConstructorArguments[0].Value :?> string |> unindentPatch }
|
||||
| _ -> None))
|
||||
|> Seq.toList
|
||||
|
||||
type Arguments =
|
||||
| [<MainCommand; ExactlyOnce>] ProjectPath of ProjectPath: string
|
||||
| Filter of SearchString: string
|
||||
| ValidateOnly
|
||||
|
||||
interface IArgParserTemplate with
|
||||
member s.Usage =
|
||||
match s with
|
||||
| ProjectPath _ -> "path/to/project.csproj|fsproj"
|
||||
| Filter _ -> "filter down to mutations that contain the given search string"
|
||||
| ValidateOnly -> "check if the patches apply, but don't run the mutations"
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
if argv.Length <> 1 then
|
||||
eprintfn "Usage: mutannot <path/to/project.csproj|fsproj>"
|
||||
exit 1
|
||||
let parsedArguments =
|
||||
ArgumentParser.Create<Arguments>(programName = "mutannot")
|
||||
|> _.ParseCommandLine(argv)
|
||||
|
||||
let projectPath = parsedArguments.GetResult ProjectPath
|
||||
let validateOnly = parsedArguments.Contains ValidateOnly
|
||||
let maybeFilter = parsedArguments.TryGetResult Filter
|
||||
|
||||
ensureCleanWorkingDirectory ()
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit.Add(fun _ -> restore ())
|
||||
|
||||
let projectPath = argv[0]
|
||||
let filteredMutations =
|
||||
getMutationCases projectPath
|
||||
|> Seq.filter _.Patch.Contains(maybeFilter |> Option.defaultValue "")
|
||||
|> Seq.indexed
|
||||
|
||||
for index, mutationCase in filteredMutations do
|
||||
Console.ForegroundColor <- ConsoleColor.Green
|
||||
printf $"MUTATION {index + 1}\n"
|
||||
|
||||
Console.ForegroundColor <- ConsoleColor.Magenta
|
||||
printf "Test:\n"
|
||||
Console.ResetColor()
|
||||
printf "%s\n\n" mutationCase.TestName
|
||||
|
||||
Console.ForegroundColor <- ConsoleColor.Magenta
|
||||
printf "Patch:\n"
|
||||
Console.ResetColor()
|
||||
printf "%s\n" mutationCase.Patch
|
||||
|
||||
for mutationCase in getMutationCases projectPath do
|
||||
printfn "MUTATION\n\n%s" <| mutationCase.Patch
|
||||
applyPatch mutationCase.Patch
|
||||
runTest projectPath mutationCase.TestName
|
||||
|
||||
if not validateOnly then
|
||||
Console.ForegroundColor <- ConsoleColor.Magenta
|
||||
printf "Output:\n"
|
||||
Console.ResetColor()
|
||||
|
||||
match runTest projectPath mutationCase.TestName with
|
||||
| 0 ->
|
||||
Console.ForegroundColor <- ConsoleColor.Red
|
||||
eprintf "ERROR: Expected tested to fail, but it succeeded\n"
|
||||
Console.ResetColor()
|
||||
exit 3
|
||||
| _ ->
|
||||
Console.ForegroundColor <- ConsoleColor.Green
|
||||
printf "✓ Mutant killed\n\n"
|
||||
|
||||
restore ()
|
||||
|
||||
Console.ForegroundColor <- ConsoleColor.Green
|
||||
|
||||
if validateOnly then
|
||||
printf "Success: All mutantions valid\n"
|
||||
else
|
||||
printf "Success: All mutants killed\n"
|
||||
|
||||
Console.ResetColor()
|
||||
|
||||
0
|
||||
|
|
|
|||
27
Mutannot/deps.json
Normal file
27
Mutannot/deps.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
[
|
||||
{
|
||||
"pname": "Argu",
|
||||
"version": "6.2.5",
|
||||
"hash": "sha256-5HcZcvco4e8+hgLhzlxk7ZmFVLtZL9LVr7LbmXsLmNU="
|
||||
},
|
||||
{
|
||||
"pname": "Fli",
|
||||
"version": "1.1000.0",
|
||||
"hash": "sha256-LKJ2raQJuNfJKOA6Y85tECMnUFuKsmd5fBOG2Sq5OjY="
|
||||
},
|
||||
{
|
||||
"pname": "System.Configuration.ConfigurationManager",
|
||||
"version": "4.4.0",
|
||||
"hash": "sha256-+8wGYllXnIxRzy9dLhZFB88GoPj8ivYXS0KUfcivT8I="
|
||||
},
|
||||
{
|
||||
"pname": "System.Reflection.MetadataLoadContext",
|
||||
"version": "9.0.1",
|
||||
"hash": "sha256-kWm31a0unw/H8SjxaabVYKInR40bTAL9JnGQEVQGTsU="
|
||||
},
|
||||
{
|
||||
"pname": "System.Security.Cryptography.ProtectedData",
|
||||
"version": "4.4.0",
|
||||
"hash": "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE="
|
||||
}
|
||||
]
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{ fetchNuGet }:
|
||||
[
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "10.1.201";
|
||||
sha256 = "sha256-NzxdRJgL+5RQpUm8Y6Mc0w7sakxqThv6qHpP+u0x5x0=";
|
||||
})
|
||||
]
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
version = "0.1.0";
|
||||
src = ./Mutannot;
|
||||
projectFile = "Mutannot.fsproj";
|
||||
nugetDeps = ./Mutannot/deps.nix;
|
||||
nugetDeps = ./Mutannot/deps.json;
|
||||
executables = [ "mutannot" ];
|
||||
dotnet-sdk = pkgs.dotnet-sdk_10;
|
||||
dotnet-runtime = pkgs.dotnet-sdk_10;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue