public void MutantPlacer_ShouldPlaceWithConditionalExpression(int id) { // 1 + 8; var originalNode = SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8))); // 1 - 8; var mutatedNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8))); var mutants = new List <(Mutant, ExpressionSyntax)> { (new Mutant { Id = id, Mutation = new Mutation { ReplacementNode = mutatedNode } }, mutatedNode) }; var result = MutantPlacer.PlaceExpressionControlledMutations(originalNode, mutants); result.ToFullString() .ShouldBeSemantically(@$ "({CodeInjection.HelperNamespace}.MutantControl.IsActive({id})?1-8:1+8)"); var removedResult = MutantPlacer.RemoveMutant(result); removedResult.ToString().ShouldBeSemantically(originalNode.ToString()); }
public void MutantPlacer_ShouldPlaceWithIfStatement(int id) { // 1 + 8; var originalNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); // 1 - 8; var mutatedNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); var result = MutantPlacer.PlaceWithIfStatement(originalNode, mutatedNode, id); result.ToFullString().ShouldBeSemantically(@"if (System.Environment.GetEnvironmentVariable(""ActiveMutation"") == """ + id.ToString() + @""") { 1 - 8; } else { 1 + 8; }"); var removedResult = MutantPlacer.RemoveByIfStatement(result); removedResult.ToString().ShouldBeSemantically(originalNode.ToString()); }
protected override SyntaxNode InjectMutations(AccessorDeclarationSyntax sourceNode, SyntaxNode targetNode, MutationContext context) { var result = base.InjectMutations(sourceNode, targetNode, context) as AccessorDeclarationSyntax; if (result?.Body == null && result?.ExpressionBody == null) { return(result); } if (!context.HasStatementLevelMutant) { return(result); } // we need to inject static marker if (result.Body == null) { result = MutantPlacer.ConvertExpressionToBody(result); } var converter = sourceNode.NeedsReturn() ? (Func <Mutation, StatementSyntax>)((toConvert) => SyntaxFactory.ReturnStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert))) : (toConvert) => SyntaxFactory.ExpressionStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert)); var newBody = MutantPlacer.PlaceStatementControlledMutations(result.Body, context.StatementLevelControlledMutations.Union(context.BlockLevelControlledMutations). Select(m => (m.Id, converter(m.Mutation)))); context.BlockLevelControlledMutations.Clear(); context.StatementLevelControlledMutations.Clear(); return(result.WithBody(SyntaxFactory.Block(newBody))); }
internal override SyntaxNode OrchestrateMutation(ConstructorDeclarationSyntax node, MutationContext context) { if (!context.MustInjectCoverageLogic) { return(context.EnterStatic().MutateNodeAndChildren(node)); } var trackedConstructor = node.TrackNodes((SyntaxNode)node.Body ?? node.ExpressionBody); if (node.ExpressionBody != null) { var bodyBlock = SyntaxFactory.Block(SyntaxFactory.ExpressionStatement(node.ExpressionBody.Expression)); var markedBlock = MutantPlacer.PlaceStaticContextMarker((BlockSyntax)context.MutateNodeAndChildren(bodyBlock)); trackedConstructor = trackedConstructor.Update( trackedConstructor.AttributeLists, trackedConstructor.Modifiers, trackedConstructor.Identifier, trackedConstructor.ParameterList, trackedConstructor.Initializer, markedBlock, null, SyntaxFactory.Token(SyntaxKind.None)); } else if (node.Body != null) { var markedBlock = MutantPlacer.PlaceStaticContextMarker((BlockSyntax)context.MutateNodeAndChildren(node.Body)); trackedConstructor = trackedConstructor.ReplaceNode(trackedConstructor.GetCurrentNode(node.Body), markedBlock); } return(trackedConstructor); }
protected override BasePropertyDeclarationSyntax InjectMutations(PropertyDeclarationSyntax sourceNode, BasePropertyDeclarationSyntax targetNode, MutationContext context) { var result = base.InjectMutations(sourceNode, targetNode, context); if (!context.HasStatementLevelMutant) { return(result); } var mutated = result as PropertyDeclarationSyntax; if (mutated?.ExpressionBody == null) { return(result); } mutated = MutantPlacer.ConvertPropertyExpressionToBodyAccessor(mutated); var getter = mutated.GetAccessor(); result = mutated.ReplaceNode(getter.Body !, SyntaxFactory.Block( MutantPlacer.PlaceStatementControlledMutations( getter.Body, context.StatementLevelControlledMutations.Union(context.BlockLevelControlledMutations).Select( m => (m.Id, SyntaxFactory.ReturnStatement( sourceNode.ExpressionBody !.Expression .InjectMutation(m.Mutation)) as StatementSyntax))))) .WithSemicolonToken(SyntaxFactory.MissingToken(SyntaxKind.SemicolonToken)); return(result); }
/// <inheritdoc/> /// Inject mutations and convert expression body to block body if required. protected override BaseMethodDeclarationSyntax InjectMutations(T sourceNode, BaseMethodDeclarationSyntax targetNode, MutationContext context) { targetNode = base.InjectMutations(sourceNode, targetNode, context); if (targetNode.Body != null) { // add a return in case we changed the control flow return(MutantPlacer.AddEndingReturn(targetNode) as T); } if (!context.HasStatementLevelMutant) { return(targetNode); } // we need to move to a body version of the method targetNode = MutantPlacer.ConvertExpressionToBody(targetNode); StatementSyntax mutatedBlock = targetNode.Body; var converter = targetNode.NeedsReturn() ? (Func <Mutation, StatementSyntax>)((toConvert) => SyntaxFactory.ReturnStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert))) : (toConvert) => SyntaxFactory.ExpressionStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert)); mutatedBlock = MutantPlacer.PlaceStatementControlledMutations(mutatedBlock, context.StatementLevelControlledMutations.Union(context.BlockLevelControlledMutations). Select(m => (m.Id, converter(m.Mutation)))); context.BlockLevelControlledMutations.Clear(); context.StatementLevelControlledMutations.Clear(); return(targetNode.ReplaceNode(targetNode.Body !, SyntaxFactory.Block(mutatedBlock))); }
internal override SyntaxNode OrchestrateMutation(PropertyDeclarationSyntax node, MutationContext context) { if (!context.MustInjectCoverageLogic) { return(context.MutateNodeAndChildren(node)); } var trackedNode = node.TrackNodes(node.AccessorList.Accessors.Select(x => (SyntaxNode)x.Body ?? x.ExpressionBody).Where(x => x != null)); foreach (var accessor in node.AccessorList.Accessors) { if (accessor.ExpressionBody != null) { var markedBlock = context.MutateNodeAndChildren(accessor.ExpressionBody); trackedNode = trackedNode.ReplaceNode(trackedNode.GetCurrentNode(accessor.ExpressionBody), markedBlock); } else if (accessor.Body != null) { var markedBlock = MutantPlacer.PlaceStaticContextMarker((BlockSyntax)context.MutateNodeAndChildren(accessor.Body)); trackedNode = trackedNode.ReplaceNode(trackedNode.GetCurrentNode(accessor.Body), markedBlock); } } return(trackedNode); }
protected override LocalFunctionStatementSyntax InjectMutations(LocalFunctionStatementSyntax sourceNode, LocalFunctionStatementSyntax targetNode, MutationContext context) { // find out parameters targetNode = base.InjectMutations(sourceNode, targetNode, context); var fullTargetBody = targetNode.Body; var sourceNodeParameterList = sourceNode.ParameterList; if (fullTargetBody != null) { // the function is in the body form // inject initialization to default for all out parameters targetNode = sourceNode.WithBody(MutantPlacer.AddDefaultInitializers(fullTargetBody, sourceNodeParameterList.Parameters.Where(p => p.Modifiers.Any(m => m.Kind() == SyntaxKind.OutKeyword)))); // add a return in case we changed the control flow return(MutantPlacer.AddEndingReturn(targetNode)); } // nothing to do if there is now pending statement mutations if (!context.HasStatementLevelMutant) { return(targetNode); } // we need to move to a body version of the function to inject pending mutations targetNode = MutantPlacer.ConvertExpressionToBody(targetNode); return(targetNode.WithBody(SyntaxFactory.Block(context.InjectBlockLevelExpressionMutation(targetNode.Body, sourceNode.ExpressionBody.Expression, sourceNode.NeedsReturn())))); }
public void ShouldRollBackFailedConstructor() { var source = @"class Test { static TestClass()=> Value-='a';}"; var orchestrator = new CsharpMutantOrchestrator(options: new StrykerOptions { OptimizationMode = OptimizationModes.CoverageBasedTest, MutationLevel = MutationLevel.Complete }); var actualNode = orchestrator.Mutate(CSharpSyntaxTree.ParseText(source).GetRoot()); var node = actualNode.DescendantNodes().First(t => t is BlockSyntax); // Remove marker var restored = MutantPlacer.RemoveMutant(node); actualNode = actualNode.ReplaceNode(node, restored); // remove mutation node = actualNode.DescendantNodes().First(t => t.IsKind(SyntaxKind.IfStatement)); restored = MutantPlacer.RemoveMutant(node); actualNode = actualNode.ReplaceNode(node, restored); // remove expression to body conversion node = actualNode.DescendantNodes().First(t => t is ConstructorDeclarationSyntax); restored = MutantPlacer.RemoveMutant(node); actualNode = actualNode.ReplaceNode(node, restored); var expectedNode = CSharpSyntaxTree.ParseText(source.Replace("StrykerNamespace", CodeInjection.HelperNamespace)).GetRoot(); expectedNode.ShouldNotContainErrors(); actualNode.ShouldBeSemantically(expectedNode); actualNode.ShouldNotContainErrors(); }
private void CheckMutantPlacerProperlyPlaceAndRemoveHelpers <T, TU>(string sourceCode, string expectedCode, Func <T, T> placer, Predicate <T> condition = null) where T : SyntaxNode where TU : SyntaxNode { var actualNode = CSharpSyntaxTree.ParseText(sourceCode).GetRoot(); var node = actualNode.DescendantNodes().First(t => t is T ct && (condition == null || condition(ct))) as T; // inject helper actualNode = actualNode.ReplaceNode(node, placer(node)); actualNode.ToFullString().ShouldBeSemantically(expectedCode); TU newNode; if (typeof(TU) == typeof(T)) { newNode = actualNode.DescendantNodes().First(t => t is TU && t.ContainsAnnotations) as TU; } else { newNode = actualNode.DescendantNodes().First(t => t is T).DescendantNodes().First(t => t is TU && t.ContainsAnnotations) as TU; } // Remove helper var restored = MutantPlacer.RemoveMutant(newNode); actualNode = actualNode.ReplaceNode(newNode, restored); actualNode.ToFullString().ShouldBeSemantically(sourceCode); // try to remove again Should.Throw <InvalidOperationException>(() => MutantPlacer.RemoveMutant(restored)); }
public void MutantPlacer_ShouldPlaceWithIfStatement(int id) { // 1 + 8; var originalNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); // 1 - 8; var mutatedNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); var mutants = new List <(Mutant, StatementSyntax)> { (new Mutant { Id = id, Mutation = new Mutation { ReplacementNode = mutatedNode } }, mutatedNode) }; var result = MutantPlacer.PlaceStatementControlledMutations(originalNode, mutants); result.ToFullString().Replace(CodeInjection.HelperNamespace, "StrykerNamespace").ShouldBeSemantically("if (StrykerNamespace.MutantControl.IsActive(" + id + @")) { 1 - 8; } else { 1 + 8; }"); var removedResult = MutantPlacer.RemoveMutant(result); removedResult.ToString().ShouldBeSemantically(originalNode.ToString()); }
protected override SyntaxNode InjectMutations(AccessorDeclarationSyntax sourceNode, SyntaxNode targetNode, MutationContext context) { var result = base.InjectMutations(sourceNode, targetNode, context) as AccessorDeclarationSyntax; if (result?.Body == null && result?.ExpressionBody == null) { return(result); } if (!context.HasStatementLevelMutant) { if (result.Body != null && sourceNode.NeedsReturn()) { result = MutantPlacer.AddEndingReturn(result, sourceNode.ReturnType()); } return(result); } if (result.Body == null) { result = MutantPlacer.ConvertExpressionToBody(result); } var newBody = context.InjectBlockLevelExpressionMutation(result.Body, sourceNode.ExpressionBody !.Expression, sourceNode.NeedsReturn()); result = result.WithBody(SyntaxFactory.Block(newBody)); if (sourceNode.NeedsReturn()) { result = MutantPlacer.AddEndingReturn(result, sourceNode.ReturnType()); } return(result); }
public void MutantPlacer_ShouldPlaceWithIfStatement(int id) { // 1 + 8; var originalNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); // 1 - 8; var mutatedNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); var result = MutantPlacer.PlaceWithIfStatement(originalNode, mutatedNode, id); result.ToFullString().ShouldBeSemantically("if (" + CodeInjection.HelperNamespace + ".MutantControl.IsActive(" + id + @")) { 1 - 8; } else { 1 + 8; }"); var removedResult = MutantPlacer.RemoveMutant(result); removedResult.ToString().ShouldBeSemantically(originalNode.ToString()); }
/// <inheritdoc/> /// <remarks>Inject pending mutations that are controlled with 'if' statements.</remarks> protected override StatementSyntax InjectMutations(T sourceNode, StatementSyntax targetNode, MutationContext context) { var mutated = MutantPlacer.PlaceStatementControlledMutations(targetNode, context.StatementLevelControlledMutations.Select(m => (m.Id, (sourceNode as StatementSyntax).InjectMutation(m.Mutation)))); context.StatementLevelControlledMutations.Clear(); return(mutated); }
/// <inheritdoc/> /// <remarks>Inject all pending mutations controlled with conditional operator(s).</remarks> protected override ExpressionSyntax InjectMutations(T sourceNode, ExpressionSyntax targetNode, MutationContext context) { var result = MutantPlacer.PlaceExpressionControlledMutations( targetNode, context.ExpressionLevelMutations.Select(m => (m.Id, (ExpressionSyntax)sourceNode.InjectMutation(m.Mutation)))) as T; context.ExpressionLevelMutations.Clear(); return(result); }
private SyntaxTree RemoveMutantIfStatements(SyntaxTree originalTree, ICollection <Diagnostic> diagnosticInfo, bool devMode) { var rollbackRoot = originalTree.GetRoot(); // find all if statements to remove var brokenMutations = new Collection <SyntaxNode>(); foreach (var diagnostic in diagnosticInfo) { var brokenMutation = rollbackRoot.FindNode(diagnostic.Location.SourceSpan); var(mutationIf, mutantId) = FindMutationIfAndId(brokenMutation); if (mutationIf == null) { var errorLocation = diagnostic.Location.GetMappedLineSpan(); _logger.LogError($"Unable to rollback mutation for node {brokenMutation} with error: {diagnostic.GetMessage()} (at {errorLocation.Path}, line: {errorLocation.StartLinePosition.Line}, col: {errorLocation.StartLinePosition.Character})."); if (devMode) { _logger.LogCritical("Stryker.Net will stop (due to dev-mode option sets to true)"); throw new ApplicationException("Internal error due to failed rollback of a mutantt."); } _logger.LogError("This should not happen, please report this as an issue on github with the previous error message."); _logger.LogWarning("Safe Mode! Rolling back all mutations in method.", brokenMutation, diagnostic.GetMessage()); // backup, remove all mutants in the node var scan = new Dictionary <SyntaxNode, int>(); var initNode = FindEnclosingMember(brokenMutation) ?? brokenMutation; ScanAllMutationsIfsAndIds(initNode, scan); foreach (var entry in scan) { if (!brokenMutations.Contains(entry.Key)) { brokenMutations.Add(entry.Key); _rollbackedIds.Add(entry.Value); } } } else { if (!brokenMutations.Contains(mutationIf)) { brokenMutations.Add(mutationIf); _rollbackedIds.Add(mutantId); } } } // mark the broken mutation nodes to track var trackedTree = rollbackRoot.TrackNodes(brokenMutations); foreach (var brokenMutation in brokenMutations) { // find the mutated node in the new tree var nodeToRemove = trackedTree.GetCurrentNode(brokenMutation); // remove the mutated node using its MutantPlacer remove method and update the tree trackedTree = trackedTree.ReplaceNode(nodeToRemove, MutantPlacer.RemoveMutant(nodeToRemove)); } return(trackedTree.SyntaxTree); }
protected override BaseFieldDeclarationSyntax InjectMutations(FieldDeclarationSyntax sourceNode, BaseFieldDeclarationSyntax targetNode, MutationContext context) { var result = base.InjectMutations(sourceNode, targetNode, context); result = result.ReplaceNodes(result.Declaration.Variables.Where(v => v.Initializer != null).Select(v => v.Initializer.Value), (syntax, _) => MutantPlacer.PlaceStaticContextMarker(syntax)); return(result); }
public void ShouldInjectInitializersAndRestore() { var source = "class Test {bool Method(out int x) {x=0;}}"; var expected = "class Test {bool Method(out int x) {{x = default(int);}x=0;}}"; CheckMutantPlacerProperlyPlaceAndRemoveHelpers <BlockSyntax>(source, expected, (n) => MutantPlacer.AddDefaultInitializers(n, new[] { SyntaxFactory.Parameter(SyntaxFactory.Identifier("x")).WithType(SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)) ) })); }
internal override SyntaxNode OrchestrateMutation(MethodDeclarationSyntax node, MutationContext context) { var mutatedNode = (MethodDeclarationSyntax)context.MutateNodeAndChildren(node); if (mutatedNode.Body == null) { return(mutatedNode); } // If method return type is void skip the node if (mutatedNode.ReturnType is PredefinedTypeSyntax predefinedType && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword)) { return(mutatedNode); } if (node.Body.ContainsNodeThatVerifies(x => x.IsKind(SyntaxKind.YieldReturnStatement), false)) { // not need to add yield return at the end of an enumeration method return(mutatedNode); } if (mutatedNode.Body.Statements.Last().Kind() == SyntaxKind.ReturnStatement) { return(mutatedNode); } var returnType = mutatedNode.ReturnType; // the GenericNameSyntax node can be encapsulated by QualifiedNameSyntax nodes var genericReturn = returnType.DescendantNodesAndSelf().OfType <GenericNameSyntax>().FirstOrDefault(); if (mutatedNode.Modifiers.Any(x => x.IsKind(SyntaxKind.AsyncKeyword))) { if (genericReturn != null) { // if the method is async and returns a generic task, make the return default return the underlying type returnType = genericReturn.TypeArgumentList.Arguments.First(); } else { // if the method is async but returns a non-generic task, don't add the return default return(mutatedNode); } } var newBody = mutatedNode.Body.AddStatements( MutantPlacer.AnnotateHelper( SyntaxFactory.ReturnStatement(SyntaxFactory.DefaultExpression(returnType).WithLeadingTrivia(SyntaxFactory.Space)))); mutatedNode = mutatedNode.ReplaceNode(mutatedNode.Body, newBody); return(mutatedNode); }
private MutantInfo ExtractMutationInfo(SyntaxNode node) { var info = MutantPlacer.FindAnnotations(node); if (info.Engine == null) { return(new MutantInfo()); } Logger.LogDebug("Found mutant {id} of type '{type}' controlled by '{engine}'.", info.Id, info.Type, info.Engine); return(info); }
public void MutantPlacer_ShouldPlaceWithIfStatement(int id) { // 1 + 8; var originalNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); // 1 - 8; var mutatedNode = SyntaxFactory.ExpressionStatement(SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8)))); var result = MutantPlacer.PlaceStatementControlledMutations(originalNode, new[] { (id, (StatementSyntax)mutatedNode) });
private int?ExtractMutationIfAndId(SyntaxNode node) { var(engine, id) = MutantPlacer.FindEngine(node); if (engine == null) { return(null); } Logger.LogDebug(id == -1 ? $"Found a helper (engine:{engine})." : $"Found mutant {id} (controlled by {engine})."); return(id); }
/// <inheritdoc/> /// <remarks>Inject all pending mutations and control them with if statements.</remarks> protected override StatementSyntax InjectMutations(T sourceNode, StatementSyntax targetNode, MutationContext context) { // we inject all pending mutations var mutationsToInject = context.StatementLevelControlledMutations .Union(context.BlockLevelControlledMutations); // mutations are controlled by 'if's var blockLevelMutations = MutantPlacer.PlaceStatementControlledMutations(targetNode, mutationsToInject.Select(m => (m.Id, (sourceNode as StatementSyntax).InjectMutation(m.Mutation)))); context.BlockLevelControlledMutations.Clear(); context.StatementLevelControlledMutations.Clear(); // ensure we have a block at the end return(blockLevelMutations); }
/// <inheritdoc/> /// <remarks>Injects a static marker used for coverage information; this implies converting /// expression arrow bodied method to regular ones.</remarks> protected override BaseMethodDeclarationSyntax InjectMutations(ConstructorDeclarationSyntax sourceNode, BaseMethodDeclarationSyntax targetNode, MutationContext context) { var mutated = base.InjectMutations(sourceNode, targetNode, context); if (!context.MustInjectCoverageLogic) { return(mutated); } if (mutated.ExpressionBody != null) { // we need a body to place the marker mutated = MutantPlacer.ConvertExpressionToBody(mutated); } return(mutated.ReplaceNode(mutated.Body !, MutantPlacer.PlaceStaticContextMarker(mutated.Body))); }
protected override BasePropertyDeclarationSyntax OrchestrateChildrenMutation(PropertyDeclarationSyntax node, MutationContext context) { if (!node.IsStatic()) { return(base.OrchestrateChildrenMutation(node, context)); } var children = node.ReplaceNodes(node.ChildNodes(), (original, _) => MutateSingleNode(original, original == node.Initializer ? context.EnterStatic() : context)); if (children.Initializer != null) { children = children.ReplaceNode(children.Initializer.Value, MutantPlacer.PlaceStaticContextMarker(children.Initializer.Value)); } return(children); }
protected override AnonymousFunctionExpressionSyntax InjectMutations(AnonymousFunctionExpressionSyntax sourceNode, AnonymousFunctionExpressionSyntax targetNode, MutationContext context) { targetNode = base.InjectMutations(sourceNode, targetNode, context); if (targetNode.Block == null) { if (targetNode.ExpressionBody == null) { // only a definition (eg interface) return(targetNode); } // this is an expression body method if (!context.HasStatementLevelMutant) { // there is no statement or block level mutant, so the method control flow is not changed by mutations // there is no need to change the method in any may return(targetNode); } // we need to convert it to expression body form targetNode = MutantPlacer.ConvertExpressionToBody(targetNode); // we need to inject pending block (and statement) level mutations targetNode = targetNode.WithBody( SyntaxFactory.Block(context.InjectBlockLevelExpressionMutation(targetNode.Block, sourceNode.ExpressionBody, true))); } else { // we add an ending return, just in case targetNode = MutantPlacer.AddEndingReturn(targetNode); } if (targetNode is SimpleLambdaExpressionSyntax lambdaExpression && lambdaExpression.Parameter.Modifiers.Any(m => m.Kind() == SyntaxKind.OutKeyword)) { targetNode = targetNode.WithBody(MutantPlacer.AddDefaultInitializers(targetNode.Block, new List <ParameterSyntax> { lambdaExpression.Parameter })); }
public void MutantPlacer_ShouldPlaceWithConditionalExpression(int id) { // 1 + 8; var originalNode = SyntaxFactory.BinaryExpression(SyntaxKind.AddExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8))); // 1 - 8; var mutatedNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(8))); var result = MutantPlacer.PlaceWithConditionalExpression(originalNode, mutatedNode, id); result.ToFullString() .ShouldBeSemantically(@$ "({CodeInjection.HelperNamespace}.MutantControl.IsActive({id})?1-8:1+8)"); var removedResult = MutantPlacer.RemoveMutant(result); removedResult.ToString().ShouldBeSemantically(originalNode.ToString()); }
/// <inheritdoc/> /// Inject mutations and convert expression body to block body if required. protected override BaseMethodDeclarationSyntax InjectMutations(T sourceNode, BaseMethodDeclarationSyntax targetNode, MutationContext context) { targetNode = base.InjectMutations(sourceNode, targetNode, context); if (targetNode.Body == null) { if (targetNode.ExpressionBody == null) { // only a definition (eg interface) return(targetNode); } // this is an expression body method if (!context.HasStatementLevelMutant) { // there is no statement or block level mutant, so the method control flow is not changed by mutations // there is no need to change the method in any may return(targetNode); } // we need to convert it to expression body form targetNode = MutantPlacer.ConvertExpressionToBody(targetNode); // we need to inject pending block (and statement) level mutations targetNode = targetNode.WithBody( SyntaxFactory.Block(context.InjectBlockLevelExpressionMutation(targetNode.Body, sourceNode.ExpressionBody?.Expression, sourceNode.NeedsReturn()))); } else { // we add an ending return, just in case targetNode = MutantPlacer.AddEndingReturn(targetNode); } // inject initialization to default for all out parameters targetNode = targetNode.WithBody(MutantPlacer.AddDefaultInitializers(targetNode.Body, sourceNode.ParameterList.Parameters.Where(p => p.Modifiers.Any(m => m.Kind() == SyntaxKind.OutKeyword)))); return(targetNode); }
private SyntaxTree RemoveMutantIfStatements(SyntaxTree originalTree, ICollection <Diagnostic> diagnosticInfo) { var rollbackRoot = originalTree.GetRoot(); // find all if statements to remove var brokenMutations = new Collection <SyntaxNode>(); foreach (var diagnostic in diagnosticInfo) { var brokenMutation = rollbackRoot.FindNode(diagnostic.Location.SourceSpan); var(mutationIf, mutantId) = FindMutationIfAndId(brokenMutation); if (mutationIf == null) { _logger.LogError("Unable to rollback mutation for node {0} with diagnostic message {1}", brokenMutation, diagnostic.GetMessage()); } if (!brokenMutations.Contains(mutationIf)) { brokenMutations.Add(mutationIf); _rollbackedIds.Add(mutantId); } } // mark the broken mutation nodes to track var trackedTree = rollbackRoot.TrackNodes(brokenMutations); foreach (var brokenMutation in brokenMutations) { // find the mutated node in the new tree var nodeToRemove = trackedTree.GetCurrentNode(brokenMutation); // remove the mutated node using its MutantPlacer remove method and update the tree if (nodeToRemove is IfStatementSyntax) { trackedTree = trackedTree.ReplaceNode(nodeToRemove, MutantPlacer.RemoveByIfStatement(nodeToRemove)); } else if (nodeToRemove is ConditionalExpressionSyntax) { trackedTree = trackedTree.ReplaceNode(nodeToRemove, MutantPlacer.RemoveByConditionalExpression(nodeToRemove)); } } return(trackedTree.SyntaxTree); }
/// <inheritdoc/> /// Inject mutations and convert expression body to block body if required. protected override BaseMethodDeclarationSyntax InjectMutations(T sourceNode, BaseMethodDeclarationSyntax targetNode, MutationContext context) { // find out parameters targetNode = base.InjectMutations(sourceNode, targetNode, context); if (targetNode.Body != null) { // inject initialization to default for all out parameters targetNode = sourceNode.ParameterList.Parameters.Where(p => p.Modifiers.Any(m => m.Kind() == SyntaxKind.OutKeyword)) .Aggregate(targetNode, (current, parameter) => MutantPlacer.AddDefaultInitialization(current, parameter.Identifier, parameter.Type)); // add a return in case we changed the control flow return(MutantPlacer.AddEndingReturn(targetNode) as T); } if (!context.HasStatementLevelMutant) { return(targetNode); } // we need to move to a body version of the method targetNode = MutantPlacer.ConvertExpressionToBody(targetNode); StatementSyntax mutatedBlock = targetNode.Body; var converter = targetNode.NeedsReturn() ? (Func <Mutation, StatementSyntax>)((toConvert) => SyntaxFactory.ReturnStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert))) : (toConvert) => SyntaxFactory.ExpressionStatement(sourceNode.ExpressionBody !.Expression.InjectMutation(toConvert)); mutatedBlock = MutantPlacer.PlaceStatementControlledMutations(mutatedBlock, context.StatementLevelControlledMutations.Union(context.BlockLevelControlledMutations). Select(m => (m.Id, converter(m.Mutation)))); context.BlockLevelControlledMutations.Clear(); context.StatementLevelControlledMutations.Clear(); return(targetNode.ReplaceNode(targetNode.Body !, SyntaxFactory.Block(mutatedBlock))); }