Skip to content

Commit

Permalink
Merge branch 'master' into renovate/testableio.system.io.abstractions…
Browse files Browse the repository at this point in the history
….wrappers-21.x
  • Loading branch information
rouke-broersma authored Nov 8, 2024
2 parents c5ace0d + 4ba906b commit 7da0ee0
Show file tree
Hide file tree
Showing 10 changed files with 886 additions and 7 deletions.
6 changes: 6 additions & 0 deletions docs/mutations.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,9 @@ For the full list of all available regex mutations, see the [regex mutator docs]
|---------------------|---------------------|
| `x ? a : b` | `true ? a : b` |
| `x ? a : b` | `false ? a : b` |

## Collection Expressions (_collectionexpression_)
| Original | Mutated |
|---------------------|-------------|
| `[]` | `[default]` |
| `[1, 2, 3]` | `[]` |
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public async Task CSharp_NetCore_SingleTestProject()

var report = await JsonReportSerialization.DeserializeJsonReportAsync(strykerRunOutput);

CheckReportMutants(report, total: 589, ignored: 246, survived: 4, killed: 9, timeout: 2, nocoverage: 297);
CheckReportMutants(report, total: 601, ignored: 247, survived: 4, killed: 9, timeout: 2, nocoverage: 308);
CheckReportTestCounts(report, total: 11);
}

Expand Down Expand Up @@ -122,7 +122,7 @@ public async Task CSharp_NetCore_WithTwoTestProjects()

var report = await JsonReportSerialization.DeserializeJsonReportAsync(strykerRunOutput);

CheckReportMutants(report, total: 589, ignored: 105, survived: 5, killed: 11, timeout: 2, nocoverage: 435);
CheckReportMutants(report, total: 601, ignored: 105, survived: 5, killed: 11, timeout: 2, nocoverage: 447);
CheckReportTestCounts(report, total: 21);
}

Expand All @@ -141,7 +141,7 @@ public async Task CSharp_NetCore_SolutionRun()

var report = await JsonReportSerialization.DeserializeJsonReportAsync(strykerRunOutput);

CheckReportMutants(report, total: 589, ignored: 246, survived: 4, killed: 9, timeout: 2, nocoverage: 297);
CheckReportMutants(report, total: 601, ignored: 247, survived: 4, killed: 9, timeout: 2, nocoverage: 308);
CheckReportTestCounts(report, total: 23);
}

Expand Down
4 changes: 3 additions & 1 deletion src/Stryker.Abstractions/Mutator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ public enum Mutator
[MutatorDescription("String Method")]
StringMethod,
[MutatorDescription("Conditional operators")]
Conditional
Conditional,
[MutatorDescription("Collection expressions")]
CollectionExpression
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand Down Expand Up @@ -1948,4 +1951,269 @@ public void ShouldIncrementMutantCountUniquely()

secondMutant.Id.ShouldBe(firstMutant.Id + 1);
}

[TestMethod]
public void ShouldMutateCollectionExpressionSpanProperty()
{
var source = "static ReadOnlySpan<int> Value => [1, 2, 3];";

var expected =
"static ReadOnlySpan<int> Value => (StrykerNamespace.MutantControl.IsActive(0)?[]:[1,2,3]);";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateCollectionExpressionLocalsInMethod()
{
var source = """
public void M() {
int[] abc = { 5, 5 };
int[] bcd = [1, .. abc, 3];
}
""";

var expected =
"""
public void M() {
if (StrykerNamespace.MutantControl.IsActive(0)) { }
else{
if(StrykerNamespace.MutantControl.IsActive(1)){
int[] abc = {};
int[] bcd = [1, .. abc, 3];
} else {
int[] abc = { 5, 5 };
int[] bcd = (StrykerNamespace.MutantControl.IsActive(2)?[]:[1, .. abc, 3]);
}
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateImplicitCollectionExpressionInMethod()
{
var source = """
public void M() {
int[] abc = { 5, 5 };
var bcd = (int[])[1, .. abc, 3];
}
""";

var expected =
"""
public void M() {
if (StrykerNamespace.MutantControl.IsActive(0)) {
} else {
if (StrykerNamespace.MutantControl.IsActive(1)) {
int[] abc = {};
var bcd = (int[])[1, ..abc, 3];
} else {
int[] abc = {5, 5};
var bcd = (int[])(
StrykerNamespace.MutantControl.IsActive(2) ? [] : [ 1, ..abc, 3 ]);
}
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateUsedCollectionExpression()
{
var source = """
public void M() {
// Stryker disable String : Not mutation under test
Span<string> weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
}
""";

var expected =
"""
public void M() {
if (StrykerNamespace.MutantControl.IsActive(0)) {
} else {
// Stryker disable String : Not mutation under test
Span<string> weekDays = (StrykerNamespace.MutantControl.IsActive(1) ? [] : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]);
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateCollectionExpressionInManyForms()
{
var source = """
// Initialize private field:
// Stryker disable String : Not mutation under test
private static readonly ImmutableArray<string> _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
// property with expression body:
public IEnumerable<int> MaxDays =>
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
public int Sum(IEnumerable<int> values) =>
values.Sum();
public void Example()
{
// As a parameter:
int sum = Sum([1, 2, 3, 4, 5]);
}
""";

var expected =
"""
// Initialize private field:
// Stryker disable String : Not mutation under test
private static readonly ImmutableArray<string> _months =
StrykerNamespace.MutantContext.TrackValue(
() =>(StrykerNamespace.MutantControl.IsActive(0) ? [] : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]));

// property with expression body:
public IEnumerable<int> MaxDays =>
(StrykerNamespace.MutantControl.IsActive(13)
? []
: [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]);

public int Sum(IEnumerable<int> values) =>
(StrykerNamespace.MutantControl.IsActive(14) ? values.Max() : values.Sum());

public void Example() {
if (StrykerNamespace.MutantControl.IsActive(15)) {
} else {
// As a parameter:
int sum = Sum(
(StrykerNamespace.MutantControl.IsActive(16) ? [] : [ 1, 2, 3, 4, 5 ]));
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateNonConstatCollectionExpression()
{
var source = """
public void M() {
// Stryker disable String : Not mutation under test
string hydrogen = "H";
string helium = "He";
string lithium = "Li";
string beryllium = "Be";
string boron = "B";
string carbon = "C";
string nitrogen = "N";
string oxygen = "O";
string fluorine = "F";
string neon = "Ne";
string[] elements = [hydrogen, helium, lithium, beryllium, boron, carbon, nitrogen, oxygen, fluorine, neon];
}
""";

var expected =
"""
public void M() {
// Stryker disable String : Not mutation under test
if (StrykerNamespace.MutantControl.IsActive(0)) {
} else {
string hydrogen = "H";
string helium = "He";
string lithium = "Li";
string beryllium = "Be";
string boron = "B";
string carbon = "C";
string nitrogen = "N";
string oxygen = "O";
string fluorine = "F";
string neon = "Ne";
string[] elements = (StrykerNamespace.MutantControl.IsActive(11) ? [] : [
hydrogen, helium, lithium, beryllium, boron, carbon, nitrogen, oxygen,
fluorine, neon
]);
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateSpreadCollectionExpression()
{
var source = """
public void M() {
// Stryker disable String : Not mutation under test
string[] vowels = ["a", "e", "i", "o", "u"];
string[] consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "z"];
string[] alphabet = [.. vowels, .. consonants, "y"];
}
""";

var expected =
"""
public void M() {
// Stryker disable String : Not mutation under test
if (StrykerNamespace.MutantControl.IsActive(0)) {
} else {
string[] vowels = (StrykerNamespace.MutantControl.IsActive(1) ? [] : ["a", "e", "i", "o", "u"]);
string[] consonants = (StrykerNamespace.MutantControl.IsActive(7) ? [] : [
"b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "z"
]);
string[] alphabet =
(StrykerNamespace.MutantControl.IsActive(28)
? []
: [..vowels, ..consonants, "y"]);
}
}
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateImplicitCollectionExpressionParameter()
{
var source = """
public void M() {
Iter([1]);
}
public IEnumerable<T> Iter<T>(IList<T> list) { }
""";

var expected =
"""
public void M() {
if (StrykerNamespace.MutantControl.IsActive(0)) {
} else {
if (StrykerNamespace.MutantControl.IsActive(1)) {
;
} else {
Iter((StrykerNamespace.MutantControl.IsActive(2) ? [] : [ 1 ]));
}
}
}
public IEnumerable<T> Iter<T>(IList<T> list) { }
""";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateNestedImplicitCollectionExpression()
{
var source = "static int[][] Value => [[1, 2], [3]];";

var expected =
"static int[][] Value => (StrykerNamespace.MutantControl.IsActive(0)?[]:[(StrykerNamespace.MutantControl.IsActive(1)?[]:[1, 2]), (StrykerNamespace.MutantControl.IsActive(2)?[]:[3])]);";
ShouldMutateSourceInClassToExpected(source, expected);
}

[TestMethod]
public void ShouldMutateNestedExplicitCollectionExpression()
{
var source = "static int[][] Value => [[1, 2], new int[] { 3 }];";

var expected =
"static int[][] Value => (StrykerNamespace.MutantControl.IsActive(0)?[]:[(StrykerNamespace.MutantControl.IsActive(1)?[]:[1, 2]), (StrykerNamespace.MutantControl.IsActive(2)?new int[] {}:new int[] { 3 })]);";
ShouldMutateSourceInClassToExpected(source, expected);
}
}
Loading

0 comments on commit 7da0ee0

Please sign in to comment.