-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integer mutators #2968
base: master
Are you sure you want to change the base?
Integer mutators #2968
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Shouldly; | ||
using Stryker.Core.Mutators; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Xunit; | ||
|
||
namespace Stryker.Core.UnitTest.Mutators; | ||
|
||
public class IntegerNegationMutatorTests : TestBase | ||
{ | ||
[Fact] | ||
public void ShouldBeMutationLevelStandard() | ||
{ | ||
var target = new IntegerNegationMutator(); | ||
target.MutationLevel.ShouldBe(MutationLevel.Standard); | ||
} | ||
|
||
[Theory] | ||
[InlineData(10, -10)] | ||
[InlineData(-10, 10)] | ||
public void ShouldMutate(int original, int expected) | ||
{ | ||
var target = new IntegerNegationMutator(); | ||
var parent = SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(original))); | ||
|
||
var result = target.ApplyMutations(parent.DescendantNodes().First() as LiteralExpressionSyntax, null).ToList(); | ||
|
||
var mutation = result.ShouldHaveSingleItem(); | ||
|
||
mutation.ReplacementNode.ShouldBeOfType<LiteralExpressionSyntax>() | ||
.Token.Value.ShouldBe(expected); | ||
mutation.DisplayName.ShouldBe("Number negation mutation"); | ||
} | ||
|
||
[Theory] | ||
[InlineData(SyntaxKind.StringLiteralExpression)] | ||
[InlineData(SyntaxKind.CharacterLiteralExpression)] | ||
[InlineData(SyntaxKind.NullLiteralExpression)] | ||
[InlineData(SyntaxKind.DefaultLiteralExpression)] | ||
[InlineData(SyntaxKind.TrueLiteralExpression)] | ||
[InlineData(SyntaxKind.FalseLiteralExpression)] | ||
public void ShouldNotMutate(SyntaxKind original) | ||
{ | ||
var target = new IntegerNegationMutator(); | ||
|
||
var result = target.ApplyMutations(SyntaxFactory.LiteralExpression(original), null).ToList(); | ||
|
||
Assert.Empty(result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Shouldly; | ||
using Stryker.Core.Mutators; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Xunit; | ||
|
||
namespace Stryker.Core.UnitTest.Mutators; | ||
|
||
public class IntegerNullificationMutatorTests : TestBase | ||
{ | ||
[Fact] | ||
public void ShouldBeMutationLevelStandard() | ||
{ | ||
var target = new IntegerNullificationMutator(); | ||
target.MutationLevel.ShouldBe(MutationLevel.Standard); | ||
} | ||
|
||
[Theory] | ||
[InlineData(10, 0)] | ||
[InlineData(-10, 0)] | ||
public void ShouldMutate(int original, int expected) | ||
{ | ||
var target = new IntegerNullificationMutator(); | ||
|
||
var parent = SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(original))); | ||
|
||
var result = target.ApplyMutations(parent.DescendantNodes().First() as LiteralExpressionSyntax, null).ToList(); | ||
|
||
var mutation = result.ShouldHaveSingleItem(); | ||
|
||
mutation.ReplacementNode.ShouldBeOfType<LiteralExpressionSyntax>() | ||
.Token.Value.ShouldBe(expected); | ||
mutation.DisplayName.ShouldBe("Integer nullification mutation"); | ||
} | ||
|
||
[Theory] | ||
[InlineData("array[1]")] | ||
public void ShouldNotMutate(string expression) | ||
{ | ||
var target = new IntegerNullificationMutator(); | ||
|
||
var parent = SyntaxFactory.ParseExpression(expression); | ||
var child = parent.DescendantNodes(_ => true).OfType<LiteralExpressionSyntax>().FirstOrDefault(); | ||
|
||
|
||
var result = target.ApplyMutations(child, null).ToList(); | ||
|
||
Assert.Empty(result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Stryker.Core.Mutants; | ||
|
||
namespace Stryker.Core.Mutators; | ||
|
||
public class IntegerNegationMutator : MutatorBase<LiteralExpressionSyntax> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why having two separate mutators? |
||
{ | ||
public override MutationLevel MutationLevel => MutationLevel.Standard; | ||
|
||
public override IEnumerable<Mutation> ApplyMutations(LiteralExpressionSyntax node, SemanticModel semanticModel) | ||
{ | ||
if (!IsNumberLiteral(node) || node.Token.Value is not (int currentValue and not 0)) | ||
{ | ||
yield break; | ||
} | ||
|
||
var replacementValue = -currentValue; | ||
yield return new Mutation | ||
{ | ||
OriginalNode = node, | ||
ReplacementNode = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(replacementValue)), | ||
DisplayName = "Number negation mutation", | ||
Type = Mutator.Number | ||
}; | ||
} | ||
|
||
private static bool IsNumberLiteral(LiteralExpressionSyntax node) | ||
{ | ||
var kind = node.Kind(); | ||
return kind == SyntaxKind.NumericLiteralExpression && node.Parent is EqualsValueClauseSyntax; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why limiting this mutation to assignment ? it seems that it could be uses within any expression (excluding indexed access |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Stryker.Core.Mutants; | ||
|
||
namespace Stryker.Core.Mutators; | ||
|
||
public class IntegerNullificationMutator : MutatorBase<LiteralExpressionSyntax> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why having two separate mutators ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured they can possibly be conflicting, and so I thought it'd be a good idea to add them separately. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stryker's mutation orchestration takes care of this. A mutator needs only to generate a mutated version of some syntax construct. |
||
{ | ||
public override MutationLevel MutationLevel => MutationLevel.Standard; | ||
|
||
public override IEnumerable<Mutation> ApplyMutations(LiteralExpressionSyntax node, SemanticModel semanticModel) | ||
{ | ||
if (IsNumberLiteral(node) && node.Token.Value is int value && value != 0) | ||
{ | ||
yield return new Mutation | ||
{ | ||
OriginalNode = node, | ||
ReplacementNode = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)), | ||
DisplayName = "Integer nullification mutation", | ||
Type = Mutator.Number | ||
}; | ||
} | ||
} | ||
|
||
private static bool IsNumberLiteral(LiteralExpressionSyntax node) | ||
{ | ||
var kind = node.Kind(); | ||
return kind == SyntaxKind.NumericLiteralExpression && node.Parent is EqualsValueClauseSyntax; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why limiting this mutation to assignment ? it seems that it could be uses within any expression. It should at least also support method arguments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great idea! initially, I didn't have a constraint on the node parent at all so all occurrences would be mutated. I then constrained it to at least work for the example in the original issue, and I kinda left it open for suggestions if other places should receive this mutation as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. limitation should only be placed if one detect an actual issue. But most (if not all) risky constructs, such as constants or attributes, are already identified and dealt with. |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have recently migrated all unit tests from xunit to mstest, sorry! Could you migrate your unit tests to mstest?