diff --git a/.gitignore b/.gitignore index 2b749db..33afe2c 100644 --- a/.gitignore +++ b/.gitignore @@ -211,6 +211,3 @@ FakesAssemblies/ # Codex .codex - -# Nix -result diff --git a/Example.Tests/Calculator.fs b/Example.Tests/Calculator.fs new file mode 100644 index 0000000..cfcce3b --- /dev/null +++ b/Example.Tests/Calculator.fs @@ -0,0 +1,10 @@ +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) diff --git a/Example.Tests/CalculatorTests.fs b/Example.Tests/CalculatorTests.fs new file mode 100644 index 0000000..0a96e10 --- /dev/null +++ b/Example.Tests/CalculatorTests.fs @@ -0,0 +1,27 @@ +namespace Example.Tests + +open Example +open Mutannot +open Xunit + +type CalculatorTests() = + [] + [= 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) diff --git a/Example/Example.fsproj b/Example.Tests/Example.Tests.fsproj similarity index 100% rename from Example/Example.fsproj rename to Example.Tests/Example.Tests.fsproj diff --git a/Example/MutationCaseAttribute.fs b/Example.Tests/MutationCaseAttribute.fs similarity index 100% rename from Example/MutationCaseAttribute.fs rename to Example.Tests/MutationCaseAttribute.fs diff --git a/Example/Calculator.fs b/Example/Calculator.fs deleted file mode 100644 index 6f0c515..0000000 --- a/Example/Calculator.fs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Example - -module Calculator = - let addOne value = value + 1 diff --git a/Example/CalculatorTests.fs b/Example/CalculatorTests.fs deleted file mode 100644 index 9029f0e..0000000 --- a/Example/CalculatorTests.fs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Example - -open Example -open Mutannot -open Xunit - -type CalculatorTests() = - [] - [] - member _.AddOne_increments() = Assert.Equal(42, Calculator.addOne 41) diff --git a/Mutannot/Mutannot.fsproj b/Mutannot/Mutannot.fsproj index 396d322..7c6381b 100644 --- a/Mutannot/Mutannot.fsproj +++ b/Mutannot/Mutannot.fsproj @@ -11,7 +11,6 @@ - diff --git a/Mutannot/Program.fs b/Mutannot/Program.fs index 118570e..13666be 100644 --- a/Mutannot/Program.fs +++ b/Mutannot/Program.fs @@ -3,7 +3,6 @@ open System.IO open System.Reflection open System.Runtime.InteropServices open Fli -open Argu type MutationCase = { TestName: string; Patch: string } @@ -56,7 +55,7 @@ let runTest projectPath testName = Output(new StreamWriter(Console.OpenStandardOutput())) } |> Command.execute - |> Output.toExitCode + |> ignore let getAssemblyPath projectPath = cli { @@ -80,7 +79,7 @@ let getMetadataLoadContext (assemblyPath: string) = new MetadataLoadContext(pathAssemblyResolver, typeof.Assembly.GetName().Name) -let unindentPatch (s: string) = +let unindented (s: string) = let lines = s.Split([| "\r\n"; "\n" |], StringSplitOptions.None) let indexOfFirstNonEmptyLine = @@ -115,81 +114,26 @@ let getMutationCases projectPath = | "Mutannot.MutationCaseAttribute" -> Some { TestName = $"{m.DeclaringType.FullName}.{m.Name}" - Patch = attr.ConstructorArguments[0].Value :?> string |> unindentPatch } + Patch = attr.ConstructorArguments[0].Value :?> string |> unindented } | _ -> None)) |> Seq.toList -type Arguments = - | [] 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" - [] let main argv = - let parsedArguments = - ArgumentParser.Create(programName = "mutannot") - |> _.ParseCommandLine(argv) - - let projectPath = parsedArguments.GetResult ProjectPath - let validateOnly = parsedArguments.Contains ValidateOnly - let maybeFilter = parsedArguments.TryGetResult Filter + if argv.Length <> 1 then + eprintfn "Usage: mutannot " + exit 1 ensureCleanWorkingDirectory () AppDomain.CurrentDomain.ProcessExit.Add(fun _ -> restore ()) - 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 + let projectPath = argv[0] + for mutationCase in getMutationCases projectPath do + printfn "MUTATION\n\n%s" <| mutationCase.Patch applyPatch mutationCase.Patch - - 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" - + runTest projectPath mutationCase.TestName restore () - Console.ForegroundColor <- ConsoleColor.Green - - if validateOnly then - printf "Success: All mutantions valid\n" - else - printf "Success: All mutants killed\n" - - Console.ResetColor() - 0 diff --git a/Mutannot/deps.json b/Mutannot/deps.json deleted file mode 100644 index 8d83a9c..0000000 --- a/Mutannot/deps.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "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=" - } -] diff --git a/Mutannot/deps.nix b/Mutannot/deps.nix new file mode 100644 index 0000000..60de7f1 --- /dev/null +++ b/Mutannot/deps.nix @@ -0,0 +1,8 @@ +{ fetchNuGet }: +[ + (fetchNuGet { + pname = "FSharp.Core"; + version = "10.1.201"; + sha256 = "sha256-NzxdRJgL+5RQpUm8Y6Mc0w7sakxqThv6qHpP+u0x5x0="; + }) +] diff --git a/flake.nix b/flake.nix index f72685d..f3fe06f 100644 --- a/flake.nix +++ b/flake.nix @@ -27,7 +27,7 @@ version = "0.1.0"; src = ./Mutannot; projectFile = "Mutannot.fsproj"; - nugetDeps = ./Mutannot/deps.json; + nugetDeps = ./Mutannot/deps.nix; executables = [ "mutannot" ]; dotnet-sdk = pkgs.dotnet-sdk_10; dotnet-runtime = pkgs.dotnet-sdk_10;