diff --git a/.gitignore b/.gitignore
index 14e94713d..93dae7365 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,10 @@ test-results/
playwright-report/
blob-report/
playwright/.cache/
+/packages/metrics-dotnet/Mutation.Metrics.CLI/bin
+/packages/metrics-dotnet/Mutation.Metrics.CLI/obj
+/packages/metrics-dotnet/Mutation.Metrics.Tests/bin
+/packages/metrics-dotnet/Mutation.Metrics.Tests/obj
+/packages/metrics-dotnet/MutationMetrics/.vs
+/packages/metrics-dotnet/MutationMetrics/bin
+/packages/metrics-dotnet/MutationMetrics/obj
diff --git a/packages/metrics-dotnet/Mutation.Metrics.CLI/Mutation.Metrics.CLI.csproj b/packages/metrics-dotnet/Mutation.Metrics.CLI/Mutation.Metrics.CLI.csproj
new file mode 100644
index 000000000..86b5a02d3
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.CLI/Mutation.Metrics.CLI.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/packages/metrics-dotnet/Mutation.Metrics.CLI/Program.cs b/packages/metrics-dotnet/Mutation.Metrics.CLI/Program.cs
new file mode 100644
index 000000000..df8f75483
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.CLI/Program.cs
@@ -0,0 +1,13 @@
+using Mutation.Metrics.Core;
+using System.Text.Json;
+
+
+for (int i = 0; i < args?.Length; i++)
+{
+ if (args[i] == "--reporter")
+ {
+ var report = Metrics.GenerateScore(args[i+1]);
+ var json = JsonSerializer.Serialize(report);
+ Console.WriteLine(json);
+ }
+}
diff --git a/packages/metrics-dotnet/Mutation.Metrics.Tests/GlobalUsings.cs b/packages/metrics-dotnet/Mutation.Metrics.Tests/GlobalUsings.cs
new file mode 100644
index 000000000..8c927eb74
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.Tests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/packages/metrics-dotnet/Mutation.Metrics.Tests/Metrics/MetricsTest.cs b/packages/metrics-dotnet/Mutation.Metrics.Tests/Metrics/MetricsTest.cs
new file mode 100644
index 000000000..75e0cca0e
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.Tests/Metrics/MetricsTest.cs
@@ -0,0 +1,15 @@
+using FluentAssertions;
+
+namespace Mutation.Metrics.Core
+{
+ public class MetricsTest
+ {
+
+ [Fact]
+ public void Metrics_GenerateScore_Success()
+ {
+ var result = Metrics.GenerateScore("ReportSample//stryker-report.json");
+ result.Covered.Should().Be(24);
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/metrics-dotnet/Mutation.Metrics.Tests/Mutation.Metrics.Tests.csproj b/packages/metrics-dotnet/Mutation.Metrics.Tests/Mutation.Metrics.Tests.csproj
new file mode 100644
index 000000000..e8497e7c6
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.Tests/Mutation.Metrics.Tests.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/packages/metrics-dotnet/Mutation.Metrics.Tests/ReportSample/stryker-report.json b/packages/metrics-dotnet/Mutation.Metrics.Tests/ReportSample/stryker-report.json
new file mode 100644
index 000000000..5d698ec36
--- /dev/null
+++ b/packages/metrics-dotnet/Mutation.Metrics.Tests/ReportSample/stryker-report.json
@@ -0,0 +1,1378 @@
+{
+ "schemaVersion": "2",
+ "thresholds": {
+ "high": 80,
+ "low": 60
+ },
+ "projectRoot": "/home/user/src/project/",
+ "files": {
+ "/home/user/src/project/1/SomeFile0.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "1",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "2",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "3",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "4",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "5",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "6",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/1/SomeFile1.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "7",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "8",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "9",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "10",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "11",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "12",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/1/SomeFile2.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "13",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "14",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "15",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "16",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "17",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "18",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/1/SomeFile3.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "19",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "20",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "21",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "22",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "23",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "24",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/1/SomeFile4.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "25",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "26",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "27",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "28",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "29",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "30",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/1/SomeFile5.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "31",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "32",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "33",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "34",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "35",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "36",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile0.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "37",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "38",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "39",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "40",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "41",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "42",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile1.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "43",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "44",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "45",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "46",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "47",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "48",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile2.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "49",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "50",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "51",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "52",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "53",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "54",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile3.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "55",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "56",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "57",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "58",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "59",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "60",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile4.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "61",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "62",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "63",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "64",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "65",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "66",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ },
+ "/home/user/src/project/2/SomeFile5.cs": {
+ "language": "cs",
+ "source": "void M(){ int i = 0 \u002B 8; }",
+ "mutants": [
+ {
+ "id": "67",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "68",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "69",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "70",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Killed",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "71",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ },
+ {
+ "id": "72",
+ "mutatorName": "This name should display",
+ "replacement": "0 -8",
+ "location": {
+ "start": {
+ "line": 1,
+ "column": 19
+ },
+ "end": {
+ "line": 1,
+ "column": 24
+ }
+ },
+ "status": "Survived",
+ "static": false,
+ "killedBy": []
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/metrics-dotnet/MutationMetrics/Metrics.cs b/packages/metrics-dotnet/MutationMetrics/Metrics.cs
new file mode 100644
index 000000000..ec8594c76
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/Metrics.cs
@@ -0,0 +1,70 @@
+using Mutation.Metrics.Core.Models;
+using System.Text.Json;
+
+namespace Mutation.Metrics.Core
+{
+ public static class Metrics
+ {
+ public static MetricResult GenerateScore(string fullPath)
+ {
+ try
+ {
+ double killed = 0;
+ double timeOut = 0;
+ double survived = 0;
+ double noCoverage = 0;
+ double runtimeErrors = 0;
+ double compileErrors = 0;
+ double ignored = 0;
+ double pending = 0;
+
+ using StreamReader reader = new(fullPath);
+ var reporterFile = reader.ReadToEnd();
+
+ JsonReport report = JsonSerializer.Deserialize(reporterFile, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+
+ foreach (var files in (report.Files))
+ {
+ foreach (var mutants in files.Value.Mutants)
+ {
+ var status = Enum.Parse(mutants.Status);
+ switch (status)
+ {
+ case MutantStatus.Killed:
+ killed++;
+ break;
+ case MutantStatus.Timeout:
+ timeOut++;
+ break;
+ case MutantStatus.Survived:
+ survived++;
+ break;
+ case MutantStatus.NoCoverage:
+ noCoverage++;
+ break;
+ case MutantStatus.CompileError:
+ compileErrors++;
+ break;
+ case MutantStatus.Ignored:
+ ignored++;
+ break;
+ case MutantStatus.Pending:
+ pending++;
+ break;
+ case MutantStatus.RunTimeError:
+ runtimeErrors++;
+ break;
+ }
+ }
+ }
+ return new MetricResult(killed, timeOut, survived, noCoverage, runtimeErrors, compileErrors, ignored, pending);
+ }
+ catch (IOException e)
+ {
+ Console.WriteLine("The file could not be read:");
+ Console.WriteLine(e.Message);
+ }
+ return new MetricResult();
+ }
+ }
+}
diff --git a/packages/metrics-dotnet/MutationMetrics/Models/JsonReport.cs b/packages/metrics-dotnet/MutationMetrics/Models/JsonReport.cs
new file mode 100644
index 000000000..28712b2e4
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/Models/JsonReport.cs
@@ -0,0 +1,19 @@
+namespace Mutation.Metrics.Core.Models
+{
+ public struct JsonReport
+ {
+ public string SchemaVersion { get; set; }
+ public IDictionary Thresholds { get; set; }
+ public IDictionary Files { get; set; }
+ }
+
+ public struct SourceFile
+ {
+ public ISet Mutants { get; set; }
+ }
+
+ public struct JsonMutant
+ {
+ public string Status { get; set; }
+ }
+}
diff --git a/packages/metrics-dotnet/MutationMetrics/Models/MetricResult.cs b/packages/metrics-dotnet/MutationMetrics/Models/MetricResult.cs
new file mode 100644
index 000000000..da78e1e74
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/Models/MetricResult.cs
@@ -0,0 +1,27 @@
+namespace Mutation.Metrics.Core.Models
+{
+ public struct MetricResult
+ {
+ public double Detected { get; private set; }
+ public double Undetected { get; private set; }
+ public double Covered { get; private set; }
+ public double Valid { get; private set; }
+ public double Invalid { get; private set; }
+ public double TotalMutants { get; private set; }
+ public double MutatioScore { get; private set; }
+ public double MutatioScoreBasedOnCoveredCode { get; private set; }
+
+
+ public MetricResult(double killed, double timeOut, double survived, double noCoverage, double runtimeErrors, double compileErrors, double ignored, double pending)
+ {
+ Detected = killed + timeOut;
+ Undetected = survived + noCoverage;
+ Covered = Detected + survived;
+ Valid = Detected+ Undetected;
+ Invalid = runtimeErrors + compileErrors;
+ TotalMutants = Valid + Invalid + ignored + pending;
+ MutatioScore = (Detected / Valid) * 100;
+ MutatioScoreBasedOnCoveredCode = (Detected / Covered) * 100;
+ }
+ }
+}
diff --git a/packages/metrics-dotnet/MutationMetrics/Models/MutantStatus.cs b/packages/metrics-dotnet/MutationMetrics/Models/MutantStatus.cs
new file mode 100644
index 000000000..e58d67f91
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/Models/MutantStatus.cs
@@ -0,0 +1,14 @@
+namespace Mutation.Metrics.Core.Models
+{
+ public enum MutantStatus
+ {
+ Pending,
+ Killed,
+ Survived,
+ Timeout,
+ CompileError,
+ RunTimeError,
+ Ignored,
+ NoCoverage
+ }
+}
diff --git a/packages/metrics-dotnet/MutationMetrics/Mutation.Metrics.Core.csproj b/packages/metrics-dotnet/MutationMetrics/Mutation.Metrics.Core.csproj
new file mode 100644
index 000000000..fa71b7ae6
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/Mutation.Metrics.Core.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/packages/metrics-dotnet/MutationMetrics/MutationMetrics.sln b/packages/metrics-dotnet/MutationMetrics/MutationMetrics.sln
new file mode 100644
index 000000000..36661c28b
--- /dev/null
+++ b/packages/metrics-dotnet/MutationMetrics/MutationMetrics.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mutation.Metrics.Core", "Mutation.Metrics.Core.csproj", "{2E2712FE-1DA1-4F43-8463-64F8B4746B0D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mutation.Metrics.Tests", "..\Mutation.Metrics.Tests\Mutation.Metrics.Tests.csproj", "{E15C8608-9235-4DFA-9F36-3349F8B97A93}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mutation.Metrics.CLI", "..\Mutation.Metrics.CLI\Mutation.Metrics.CLI.csproj", "{9056BD21-9CFF-4952-BC80-48B152CAB4A8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2E2712FE-1DA1-4F43-8463-64F8B4746B0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2E2712FE-1DA1-4F43-8463-64F8B4746B0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E2712FE-1DA1-4F43-8463-64F8B4746B0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2E2712FE-1DA1-4F43-8463-64F8B4746B0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E15C8608-9235-4DFA-9F36-3349F8B97A93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E15C8608-9235-4DFA-9F36-3349F8B97A93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E15C8608-9235-4DFA-9F36-3349F8B97A93}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E15C8608-9235-4DFA-9F36-3349F8B97A93}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9056BD21-9CFF-4952-BC80-48B152CAB4A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9056BD21-9CFF-4952-BC80-48B152CAB4A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9056BD21-9CFF-4952-BC80-48B152CAB4A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9056BD21-9CFF-4952-BC80-48B152CAB4A8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D3F1A0FC-3272-415F-8D7D-6E5B68F8CA20}
+ EndGlobalSection
+EndGlobal