FileMutantsSequence points
ArithmeticOperatorTurtle.cs
1 / 1
1 / 1
BitwiseOperatorTurtle.cs
1 / 1
1 / 1
BranchConditionTurtle.cs
1 / 1
1 / 1
ConditionalBoundaryTurtle.cs
90 / 90
16 / 16
ConsoleProcessFactory.cs
93 / 93
21 / 24
InstructionExtensions.cs
85 / 85
14 / 17
MethodDefinitionResolver.cs
41 / 41
18 / 22
MethodTurtleBase.cs
10 / 10
4 / 5
Module.cs
58 / 58
16 / 17
MutationTest.cs
417 / 417
115 / 122
MutationTestBuilder.cs
4 / 4
3 / 4
OpCodeRotationTurtle.cs
64 / 64
16 / 16
SequencePointDeletionTurtle.cs
234 / 234
44 / 45
TestDirectory.cs
196 / 196
35 / 36
TypeResolver.cs
66 / 66
22 / 25
VariableReadTurtle.cs
223 / 223
47 / 47
VariableWriteTurtle.cs
182 / 182
39 / 39

ArithmeticOperatorTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : 
  24:        : using Mono.Cecil.Cil;​
  25:        : 
  26:        : namespace NinjaTurtles.Turtles​
  27:        : {​
  28:        :     /// <summary>​
  29:        :     /// An implementation of <see cref="IMethodTurtle"/> that replaces each of​
  30:        :     /// the arithmetic operators <see cref="OpCodes.Add" />,​
  31:        :     /// <see cref="OpCodes.Sub" />, <see cref="OpCodes.Mul" />,​
  32:        :     /// <see cref="OpCodes.Div" /> and <see cref="OpCodes.Rem" /> with each​
  33:        :     /// of the others in turn.​
  34:        :     /// </summary>​
  35:        :     public class ArithmeticOperatorTurtle : OpCodeRotationTurtle​
  36:        :     {​
  37:        :         /// <summary>​
  38:        :         /// Initializes a new instance of ​
  39:        :         /// <see cref="ArithmeticOperatorTurtle" />.​
  40:        :         /// </summary>​
  41:        :         public ArithmeticOperatorTurtle()​
  42:        :         {​
  43:     1/1:             _opCodes = new Dictionary<OpCode, IEnumerable<OpCode>>​
  44:     1/1:                            {​
  45:     1/1:                                {OpCodes.Add, new[] {OpCodes.Sub, OpCodes.Mul, OpCodes.Div, OpCodes.Rem}},​
  46:     1/1:                                {OpCodes.Sub, new[] {OpCodes.Add, OpCodes.Mul, OpCodes.Div, OpCodes.Rem}},​
  47:     1/1:                                {OpCodes.Mul, new[] {OpCodes.Add, OpCodes.Sub, OpCodes.Div, OpCodes.Rem}},​
  48:     1/1:                                {OpCodes.Div, new[] {OpCodes.Add, OpCodes.Sub, OpCodes.Mul, OpCodes.Rem}},​
  49:     1/1:                                {OpCodes.Rem, new[] {OpCodes.Add, OpCodes.Sub, OpCodes.Mul, OpCodes.Div}}​
  50:     1/1:                            };​
  51:        :         }​
  52:        :     }​
  53:        : }​
  54:        : 

BitwiseOperatorTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : 
  24:        : using Mono.Cecil.Cil;​
  25:        : 
  26:        : namespace NinjaTurtles.Turtles​
  27:        : {​
  28:        :     /// <summary>​
  29:        :     /// An implementation of <see cref="IMethodTurtle"/> that replaces each of​
  30:        :     /// the bitwise operators <see cref="OpCodes.Or" />,​
  31:        :     /// <see cref="OpCodes.And" /> and <see cref="OpCodes.Xor" /> with each​
  32:        :     /// of the others in turn.​
  33:        :     /// </summary>​
  34:        :     public class BitwiseOperatorTurtle : OpCodeRotationTurtle​
  35:        :     {​
  36:        :         /// <summary>​
  37:        :         /// Initializes a new instance of <see cref="BitwiseOperatorTurtle" />.​
  38:        :         /// </summary>​
  39:        :         public BitwiseOperatorTurtle()​
  40:        :         {​
  41:     1/1:             _opCodes = new Dictionary<OpCode, IEnumerable<OpCode>>​
  42:     1/1:                            {​
  43:     1/1:                                {OpCodes.Or, new[] {OpCodes.And, OpCodes.Xor}},​
  44:     1/1:                                {OpCodes.And, new[] {OpCodes.Or, OpCodes.Xor}},​
  45:     1/1:                                {OpCodes.Xor, new[] {OpCodes.Or, OpCodes.And}}​
  46:     1/1:                            };​
  47:        :         }​
  48:        :     }​
  49:        : }​

BranchConditionTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : 
  24:        : using Mono.Cecil.Cil;​
  25:        : 
  26:        : namespace NinjaTurtles.Turtles​
  27:        : {​
  28:        :     /// <summary>​
  29:        :     /// An implementation of <see cref="IMethodTurtle"/> that replaces the​
  30:        :     /// conditional branch operators​
  31:        :     /// <see cref="OpCodes.Brtrue" /> and <see cref="OpCodes.Brfalse"/> with​
  32:        :     /// their converse and with the operators <see cref="OpCodes.Br"/> (always​
  33:        :     /// branch) and <see cref="OpCodes.Nop" /> (never branch) in turn.​
  34:        :     /// </summary>​
  35:        :     public class BranchConditionTurtle : OpCodeRotationTurtle​
  36:        :     {​
  37:        :         /// <summary>​
  38:        :         /// Initializes a new instance of <see cref="BranchConditionTurtle" />.​
  39:        :         /// </summary>​
  40:        :         public BranchConditionTurtle()​
  41:        :         {​
  42:     1/1:             _opCodes = new Dictionary<OpCode, IEnumerable<OpCode>>​
  43:     1/1:                            {​
  44:     1/1:                                {OpCodes.Brtrue, new[] {OpCodes.Nop, OpCodes.Brfalse, OpCodes.Br}},​
  45:     1/1:                                {OpCodes.Brfalse, new[] {OpCodes.Nop, OpCodes.Brtrue, OpCodes.Br}}​
  46:     1/1:                            };​
  47:        :         }​
  48:        :     }​
  49:        : }​

ConditionalBoundaryTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : 
  24:        : using Mono.Cecil;​
  25:        : using Mono.Cecil.Cil;​
  26:        : 
  27:        : namespace NinjaTurtles.Turtles​
  28:        : {​
  29:        :     /// <summary>​
  30:        :     /// An implementation of <see cref="IMethodTurtle"/> that changes​
  31:        :     /// whether or not equality is included in comparison operators, so​
  32:        :     /// for example <see cref="OpCodes.Clt" /> is replaced by a combination​
  33:        :     /// of <see cref="OpCodes.Cgt" /> and a comparison with zero to give the​
  34:        :     /// effect of a &lt;= operator.​
  35:        :     /// </summary>​
  36:        :     public class ConditionalBoundaryTurtle : MethodTurtleBase​
  37:        :     {​
  38:        :         /// <summary>​
  39:        :         /// Performs the actual code mutations, returning each with​
  40:        :         /// <c>yield</c> for the calling code to use.​
  41:        :         /// </summary>​
  42:        :         /// <remarks>​
  43:        :         /// Implementing classes should yield the result obtained by calling​
  44:        :         /// the <see mref="DoYield" /> method.​
  45:        :         /// </remarks>​
  46:        :         /// <param name="method">​
  47:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  48:        :         /// testing is to be carried out.​
  49:        :         /// </param>​
  50:        :         /// <param name="module">​
  51:        :         /// A <see cref="Module" /> representing the main module of the​
  52:        :         /// containing assembly.​
  53:        :         /// </param>​
  54:        :         /// <returns>​
  55:        :         /// An <see cref="IEnumerable{T}" /> of​
  56:        :         /// <see cref="MutantMetaData" /> structures.​
  57:        :         /// </returns>​
  58:        :         protected override IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module)​
  59:        :         {​
  60:   16/16:             for (int index = 0; index < method.Body.Instructions.Count; index++)​
  61:        :             {​
  62:     4/4:                 var instruction = method.Body.Instructions[index];​
  63:   13/13:                 if (instruction.OpCode == OpCodes.Clt​
  64:   13/13:                     || instruction.OpCode == OpCodes.Cgt)​
  65:        :                 {​
  66:     3/3:                     var originalCode = instruction.OpCode.Code;​
  67:        : 
  68:     3/3:                     var loadZero = method.Body.GetILProcessor().Create(OpCodes.Ldc_I4_0);​
  69:     3/3:                     var compareEqual = method.Body.GetILProcessor().Create(OpCodes.Ceq);​
  70:        : 
  71:     8/8:                     method.Body.Instructions.Insert(index + 1, compareEqual);​
  72:     8/8:                     method.Body.Instructions.Insert(index + 1, loadZero);​
  73:        : 
  74:     8/8:                     instruction.OpCode = instruction.OpCode == OpCodes.Clt ? OpCodes.Cgt : OpCodes.Clt;​
  75:        : 
  76:     4/4:                     var description = string.Format("{0:x4}: {1} => not {2}", GetOriginalOffset(index), originalCode, instruction.OpCode.Code);​
  77:     4/4:                     yield return DoYield(method, module, description, index);​
  78:        : 
  79:     8/8:                     instruction.OpCode = instruction.OpCode == OpCodes.Clt ? OpCodes.Cgt : OpCodes.Clt;​
  80:        : 
  81:     3/3:                     method.Body.Instructions.Remove(compareEqual);​
  82:     3/3:                     method.Body.Instructions.Remove(loadZero);​
  83:        :                 }​
  84:        :             }​
  85:        :         }​
  86:        :     }​
  87:        : }​

ConsoleProcessFactory.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Diagnostics;​
  25:        : using System.IO;​
  26:        : 
  27:        : namespace NinjaTurtles​
  28:        : {​
  29:        :     /// <summary>​
  30:        :     /// A factory class used to instatiate a <see cref="Process" /> instance,​
  31:        :     /// taking into account the operating system and runtime.​
  32:        :     /// </summary>​
  33:        :     public static class ConsoleProcessFactory​
  34:        :     {​
  35:        :         internal static bool IsMono { get; set; }​
  36:        :         internal static bool IsWindows { get; set; }​
  37:        : 
  38:        :         static ConsoleProcessFactory()​
  39:        :         {​
  40:        :             IsMono = Type.GetType("Mono.Runtime") != null;​
  41:        :             IsWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win")​
  42:        :                         || Environment.OSVersion.Platform == PlatformID.Xbox;​
  43:        :         }​
  44:        : 
  45:        :         /// <summary>​
  46:        :         /// Creates a <see cref="Process" /> instance used to execute the​
  47:        :         /// executable identifier by the <paramref name="exeName"/>​
  48:        :         /// parameter, with the <paramref name="arguments"/> specified.​
  49:        :         /// </summary>​
  50:        :         /// <param name="exeName">​
  51:        :         /// The name (and path) of the executable to run.​
  52:        :         /// </param>​
  53:        :         /// <param name="arguments">​
  54:        :         /// The command line arguments to pass to the executable.​
  55:        :         /// </param>​
  56:        :         /// <param name="additionalSearchLocations">​
  57:        :         /// An optional list of additional search paths.​
  58:        :         /// </param>​
  59:        :         /// <returns>​
  60:        :         /// An instance of <see cref="Process" />.​
  61:        :         /// </returns>​
  62:        :         public static Process CreateProcess(string exeName, string arguments, params string[] additionalSearchLocations)​
  63:        :         {​
  64:     2/2:             exeName = FindExecutable(exeName, additionalSearchLocations);​
  65:        : 
  66:     5/5:             if (IsMono)​
  67:        :             {​
  68:     3/3:                 arguments = string.Format("--runtime=v4.0 \"{0}\" {1}", exeName, arguments);​
  69:     1/1:                 exeName = "mono";​
  70:        :             }​
  71:        : 
  72:     5/5:             arguments = string.Format(arguments, IsWindows ? "/" : "-");​
  73:        : 
  74:     3/3:             var processStartInfo = new ProcessStartInfo(exeName, arguments);​
  75:     1/1:             processStartInfo.UseShellExecute = false;​
  76:     1/1:             processStartInfo.CreateNoWindow = true;​
  77:     1/1:             processStartInfo.RedirectStandardOutput = true;​
  78:        : 
  79:     4/4:             return new Process​
  80:     4/4:             {​
  81:     4/4:                 StartInfo = processStartInfo​
  82:     4/4:             };​
  83:        :         }​
  84:        : 
  85:        :         private static string FindExecutable(string exeName, string[] additionalSearchLocations)​
  86:        :         {​
  87:     1/1:             var searchPath = new List<string>();​
  88:     1/1:             searchPath.AddRange(additionalSearchLocations);​
  89:     7/7:             string environmentSearchPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;​
  90:     8/8:             searchPath.AddRange(environmentSearchPath.Split(IsWindows ? ';' : ':'));​
  91:        : 
  92:   12/12:             foreach (string folder in searchPath)​
  93:        :             {​
  94:   12/12:                 string fullExePath = Path.Combine(folder, exeName);​
  95:     9/9:                 if (File.Exists(fullExePath))​
  96:        :                 {​
  97:     8/8:                     return fullExePath;​
  98:        :                 }​
  99:        :             }​
 100:     9/9:             return exeName;​
 101:        :         }​
 102:        :     }​
 103:        : }​

InstructionExtensions.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Linq;​
  25:        : 
  26:        : using Mono.Cecil;​
  27:        : using Mono.Cecil.Cil;​
  28:        : 
  29:        : namespace NinjaTurtles​
  30:        : {​
  31:        :     internal static class InstructionExtensions​
  32:        :     {​
  33:        :         internal static  bool IsMeaninglessUnconditionalBranch(this Instruction instruction)​
  34:        :         {​
  35:     3/3:             return instruction.OpCode == OpCodes.Br​
  36:     3/3:                 && ((Instruction)instruction.Operand).Offset == instruction.Next.Offset;​
  37:        :         }​
  38:        : 
  39:        :         internal static bool FollowsSequence(this Instruction instruction, params OpCode[] sequence)​
  40:        :         {​
  41:        :             if (instruction.OpCode != sequence[0]) return false;​
  42:        :             if (sequence.Length == 1) return true;​
  43:        :             var newSequence = new OpCode[sequence.Length - 1];​
  44:        :             Array.Copy(sequence, 1, newSequence, 0, newSequence.Length);​
  45:        :             return instruction.Next.FollowsSequence(newSequence);​
  46:        :         }​
  47:        : 
  48:        :         internal static bool IsPartOfSequence(this Instruction instruction, params OpCode[] sequence)​
  49:        :         {​
  50:        :             if (!sequence.Distinct().Contains(instruction.OpCode)) return false;​
  51:        :             var startInstruction = instruction;​
  52:        :             for (int i = 0; i < sequence.Length; i++)​
  53:        :             {​
  54:        :                 if (startInstruction == null) break;​
  55:        :                 if (startInstruction.FollowsSequence(sequence)) return true;​
  56:        :                 startInstruction = startInstruction.Previous;​
  57:        :             }​
  58:        :             return false;​
  59:        :         }​
  60:        : 
  61:        :         internal static bool IsPartOfCompilerGeneratedDispose(this Instruction instruction)​
  62:        :         {​
  63:        :             if (instruction.IsPartOfSequence(OpCodes.Leave,​
  64:        :                 OpCodes.Ldloc, OpCodes.Ldnull, OpCodes.Ceq,​
  65:        :                 OpCodes.Stloc, OpCodes.Ldloc, OpCodes.Brtrue,​
  66:        :                 OpCodes.Ldloc, OpCodes.Callvirt))​
  67:        :             {​
  68:        :                 while (instruction.OpCode != OpCodes.Callvirt)​
  69:        :                 {​
  70:        :                     instruction = instruction.Next;​
  71:        :                 }​
  72:        :                 var method = ((MethodReference)instruction.Operand);​
  73:        :                 return method.Name == "Dispose";​
  74:        :             }​
  75:        :             if (instruction.IsPartOfSequence(OpCodes.Leave,​
  76:        :                 OpCodes.Ldloc, OpCodes.Ldnull, OpCodes.Ceq,​
  77:        :                 OpCodes.Brtrue,​
  78:        :                 OpCodes.Ldloc, OpCodes.Callvirt))​
  79:        :             {​
  80:        :                 while (instruction.OpCode != OpCodes.Callvirt)​
  81:        :                 {​
  82:        :                     instruction = instruction.Next;​
  83:        :                 }​
  84:        :                 var method = ((MethodReference)instruction.Operand);​
  85:        :                 return method.Name == "Dispose";​
  86:        :             }​
  87:        :             if (instruction.IsPartOfSequence(OpCodes.Nop, OpCodes.Ldc_I4, OpCodes.Stloc,​
  88:        :                 OpCodes.Leave, OpCodes.Ldarg, OpCodes.Call,​
  89:        :                 OpCodes.Nop, OpCodes.Endfinally))​
  90:        :             {​
  91:        :                 if (instruction.OpCode == OpCodes.Endfinally)​
  92:        :                 {​
  93:        :                     instruction = instruction.Previous;​
  94:        :                 }​
  95:        :                 if (instruction.Next.OpCode == OpCodes.Endfinally)​
  96:        :                 {​
  97:        :                     instruction = instruction.Previous;​
  98:        :                 }​
  99:        :                 while (instruction.OpCode != OpCodes.Call)​
 100:        :                 {​
 101:        :                     instruction = instruction.Next;​
 102:        :                 }​
 103:        :                 var method = ((MethodReference)instruction.Operand);​
 104:        :                 return method.Name == "Dispose" || method.Name == "System.IDisposable.Dispose";​
 105:        :             }​
 106:        :             return false;​
 107:        :         }​
 108:        : 
 109:        :         internal static bool ShouldReportSequencePoint(this Instruction instruction)​
 110:        :         {​
 111:     1/1:             var instructions = new List<Instruction>();​
 112:        :             do​
 113:        :             {​
 114:     9/9:                 if (instruction.OpCode != OpCodes.Nop)​
 115:        :                 {​
 116:     3/3:                     instructions.Add(instruction);​
 117:        :                 }​
 118:     3/3:                 instruction = instruction.Next;​
 119:   13/13:             } while (instruction != null && instruction.SequencePoint == null);​
 120:   10/10:             if (instructions.All(i => i.OpCode == OpCodes.Ret))​
 121:        :             {​
 122:     1/1:                 return false;​
 123:        :             }​
 124:     7/7:             if (instructions.Count == 2)​
 125:        :             {​
 126:     2/2:                 Instruction first = instructions[0];​
 127:     2/2:                 Instruction second = instructions[1];​
 128:   29/29:                 if (((first.OpCode == OpCodes.Ldarg​
 129:   29/29:                     && ((ParameterDefinition)first.Operand).Sequence == 0 )​
 130:   29/29:                     || first.OpCode == OpCodes.Ldarg_0)​
 131:   29/29:                     && second.OpCode == OpCodes.Call​
 132:   29/29:                     && ((MethodReference)second.Operand).Name == Methods.CONSTRUCTOR)​
 133:        :                 {​
 134:     1/1:                     return false;​
 135:        :                 }​
 136:        :             }​
 137:     1/1:             return true;​
 138:        :         }​
 139:        :     }​
 140:        : }​

MethodDefinitionResolver.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Linq;​
  24:        : 
  25:        : using Mono.Cecil;​
  26:        : 
  27:        : using NLog;​
  28:        : 
  29:        : namespace NinjaTurtles​
  30:        : {​
  31:        :     internal class MethodDefinitionResolver​
  32:        :     {​
  33:        :         #region Logging​
  34:        : 
  35:        :         private static Logger _log = LogManager.GetCurrentClassLogger();​
  36:        : 
  37:        :         #endregion​
  38:        : 
  39:        :         public static MethodDefinition ResolveMethod(TypeDefinition typeDefinition, string methodName)​
  40:        :         {​
  41:     1/1:             _log.Debug("Resolving method \"{0}\" in \"{1}\".", methodName, typeDefinition.FullName);​
  42:        :             try​
  43:        :             {​
  44:     5/5:                 MethodDefinition methodDefinition = typeDefinition.Methods.Single(m => m.Name == methodName);​
  45:     1/1:                 _log.Debug("Method \"{0}\" successfully resolved in \"{1}\".", methodName, typeDefinition.FullName);​
  46:     3/3:                 return methodDefinition;​
  47:        :             }​
  48:     1/1:             catch (InvalidOperationException ex)​
  49:        :             {​
  50:     5/5:                 if (ex.Message == "Sequence contains no matching element")​
  51:        :                 {​
  52:     1/1:                     _log.Error("Method \"{0}\" is unrecognised.", methodName);​
  53:     1/1:                     throw new ArgumentException(string.Format("Method \"{0}\" is unrecognised.", methodName), "methodName");​
  54:        :                 }​
  55:     1/1:                 _log.Error("Method \"{0}\" is overloaded.", methodName);​
  56:     2/2:                 throw new ArgumentException(string.Format("Method \"{0}\" is overloaded.", methodName), "methodName");​
  57:        :             }​
  58:        :         }​
  59:        : 
  60:        :         public static MethodDefinition ResolveMethod(TypeDefinition typeDefinition, string methodName, Type[] parameterTypes)​
  61:        :         {​
  62:     5/5:             if (parameterTypes == null)​
  63:        :             {​
  64:     1/1:                 _log.Warn("\"ResolveMethod\" overload with parameter types called unnecessarily.");​
  65:     2/2:                 return ResolveMethod(typeDefinition, methodName);​
  66:        :             }​
  67:        :             try​
  68:        :             {​
  69:     5/5:                 MethodDefinition methodDefinition =​
  70:     5/5:                     typeDefinition.Methods.Single(​
  71:     5/5:                         m => m.Name == methodName​
  72:     5/5:                             && Enumerable.SequenceEqual(​
  73:     5/5:                                 m.Parameters.Select(p => p.ParameterType.Name.Replace("TypeDefinition", "Type")),​
  74:     5/5:                                 parameterTypes.Select(p => p.Name)));​
  75:     1/1:                 _log.Debug("Method \"{0}\" successfully resolved in \"{1}\".", methodName, typeDefinition.FullName);​
  76:     3/3:                 return methodDefinition;​
  77:        :             }​
  78:        :             catch (InvalidOperationException)​
  79:        :             {​
  80:     1/1:                 _log.Error("Method \"{0}\" with specified parameter types is unrecognised.", methodName);​
  81:     2/2:                 throw new ArgumentException(string.Format("Method \"{0}\" with specified parameter types is unrecognised.", methodName), "methodName");​
  82:        :             }​
  83:        :         }​
  84:        :     }​
  85:        : }​

MethodTurtleBase.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Globalization;​
  25:        : using System.IO;​
  26:        : using System.Linq;​
  27:        : 
  28:        : using Mono.Cecil;​
  29:        : using Mono.Cecil.Cil;​
  30:        : using Mono.Cecil.Rocks;​
  31:        : 
  32:        : namespace NinjaTurtles.Turtles​
  33:        : {​
  34:        :     /// <summary>​
  35:        :     /// An abstract base class for implementations of​
  36:        :     /// <see cref="IMethodTurtle" />.​
  37:        :     /// </summary>​
  38:        :     public abstract class MethodTurtleBase : IMethodTurtle​
  39:        :     {​
  40:        :         private int[] _originalOffsets;​
  41:        :         private Module _module;​
  42:        :         private MethodDefinition _method;​
  43:        : 
  44:        :         internal void MutantComplete(MutantMetaData metaData)​
  45:        :         {​
  46:     1/1:             metaData.TestDirectory.Dispose();​
  47:        :         }​
  48:        : 
  49:        :         /// <summary>​
  50:        :         /// Returns an <see cref="IEnumerable{T}" /> of detailed descriptions​
  51:        :         /// of mutations, having first carried out the mutation in question and​
  52:        :         /// saved the modified assembly under test to disk.​
  53:        :         /// </summary>​
  54:        :         /// <param name="method">​
  55:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  56:        :         /// testing is to be carried out.​
  57:        :         /// </param>​
  58:        :         /// <param name="module">​
  59:        :         /// A <see cref="Module" /> representing the main module of the​
  60:        :         /// containing assembly.​
  61:        :         /// </param>​
  62:        :         /// <param name="originalOffsets">​
  63:        :         /// An array of the original IL offsets before macros were expanded.​
  64:        :         /// </param>​
  65:        :         /// <returns>​
  66:        :         /// An <see cref="IEnumerable{T}" /> of​
  67:        :         /// <see cref="MutantMetaData" /> structures.​
  68:        :         /// </returns>​
  69:        :         public IEnumerable<MutantMetaData> Mutate(MethodDefinition method, Module module, int[] originalOffsets)​
  70:        :         {​
  71:        :             _module = module;​
  72:        :             _method = method;​
  73:        :             _originalOffsets = originalOffsets;​
  74:        :             method.Body.SimplifyMacros();​
  75:        :             foreach (var mutation in DoMutate(method, module))​
  76:        :             {​
  77:        :                 yield return mutation;​
  78:        :             }​
  79:        :             method.Body.OptimizeMacros();​
  80:        :             var nestedType =​
  81:        :                 method.DeclaringType.NestedTypes.FirstOrDefault(​
  82:        :                     t => t.Name.StartsWith(string.Format("<{0}>", method.Name))​
  83:        :                     && t.Interfaces.Any(i => i.Name == "IEnumerable`1"));​
  84:        :             if (nestedType != null)​
  85:        :             {​
  86:        :                 var nestedMethod = nestedType.Methods.First(m => m.Name == "MoveNext");​
  87:        :                 _originalOffsets = nestedMethod.Body.Instructions.Select(i => i.Offset).ToArray();​
  88:        :                 _method = nestedMethod;​
  89:        :                 nestedMethod.Body.SimplifyMacros();​
  90:        :                 foreach (var mutation in DoMutate(nestedMethod, module))​
  91:        :                 {​
  92:        :                     yield return mutation;​
  93:        :                 }​
  94:        :                 nestedMethod.Body.OptimizeMacros();​
  95:        :             }​
  96:        :         }​
  97:        : 
  98:        :         /// <summary>​
  99:        :         /// Performs the actual code mutations, returning each with​
 100:        :         /// <c>yield</c> for the calling code to use.​
 101:        :         /// </summary>​
 102:        :         /// <remarks>​
 103:        :         /// Implementing classes should yield the result obtained by calling​
 104:        :         /// the <see mref="DoYield" /> method.​
 105:        :         /// </remarks>​
 106:        :         /// <param name="method">​
 107:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
 108:        :         /// testing is to be carried out.​
 109:        :         /// </param>​
 110:        :         /// <param name="module">​
 111:        :         /// A <see cref="Module" /> representing the main module of the​
 112:        :         /// containing assembly.​
 113:        :         /// </param>​
 114:        :         /// <returns>​
 115:        :         /// An <see cref="IEnumerable{T}" /> of​
 116:        :         /// <see cref="MutantMetaData" /> structures.​
 117:        :         /// </returns>​
 118:        :         protected abstract IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module);​
 119:        : 
 120:        :         /// <summary>​
 121:        :         /// A helper method that copies the test folder, and saves the mutated​
 122:        :         /// assembly under test into it before returning an instance of​
 123:        :         /// <see cref="MutantMetaData" />.​
 124:        :         /// </summary>​
 125:        :         /// <param name="method">​
 126:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
 127:        :         /// testing is to be carried out.​
 128:        :         /// </param>​
 129:        :         /// <param name="module">​
 130:        :         /// A <see cref="Module" /> representing the main module of the​
 131:        :         /// containing assembly.​
 132:        :         /// </param>​
 133:        :         /// <param name="description">​
 134:        :         /// A description of the mutation that has been applied.​
 135:        :         /// </param>​
 136:        :         /// <param name="index">​
 137:        :         /// The index of the (first) IL instruction at which the mutation was​
 138:        :         /// applied.​
 139:        :         /// </param>​
 140:        :         /// <returns></returns>​
 141:        :         protected MutantMetaData DoYield(MethodDefinition method, Module module, string description, int index)​
 142:        :         {​
 143:     1/1:             var testDirectory = new TestDirectory(Path.GetDirectoryName(module.AssemblyLocation));​
 144:     1/1:             testDirectory.SaveAssembly(module);​
 145:     7/7:             return new MutantMetaData​
 146:     7/7:             {​
 147:     7/7:                 Description = description,​
 148:     7/7:                 MethodDefinition = method,​
 149:     7/7:                 TestDirectory = testDirectory,​
 150:     7/7:                 ILIndex = index​
 151:     7/7:             };​
 152:        :         }​
 153:        : 
 154:        :         internal int GetOriginalOffset(int index)​
 155:        :         {​
 156:        :             return _originalOffsets[index];​
 157:        :         }​
 158:        : 
 159:        :         internal string GetOriginalSourceFileName(int index)​
 160:        :         {​
 161:        :             var sequencePoint = GetCurrentSequencePoint(index);​
 162:        :             return Path.GetFileName(sequencePoint.Document.Url);​
 163:        :         }​
 164:        : 
 165:        :         internal SequencePoint GetCurrentSequencePoint(int index)​
 166:        :         {​
 167:        :             var instruction = _method.Body.Instructions[index];​
 168:        :             while ((instruction.SequencePoint == null​
 169:        :                 || instruction.SequencePoint.StartLine == 0xfeefee) && index > 0)​
 170:        :             {​
 171:        :                 index--;​
 172:        :                 instruction = _method.Body.Instructions[index];​
 173:        :             }​
 174:        :             var sequencePoint = instruction.SequencePoint;​
 175:        :             return sequencePoint;​
 176:        :         }​
 177:        : 
 178:        :         internal string GetOriginalSourceCode(int index)​
 179:        :         {​
 180:        :             var sequencePoint = GetCurrentSequencePoint(index);​
 181:        :             string result = "";​
 182:        :             if (!_module.SourceFiles.ContainsKey(sequencePoint.Document.Url))​
 183:        :             {​
 184:        :                 return "";​
 185:        :             }​
 186:        :             string[] sourceCode = _module.SourceFiles[sequencePoint.Document.Url];​
 187:        :             int upperBound = Math.Min(sequencePoint.EndLine + 2, sourceCode.Length);​
 188:        :             for (int line = Math.Max(sequencePoint.StartLine - 2, 1); line <= upperBound; line++)​
 189:        :             {​
 190:        :                 string sourceLine = sourceCode[line - 1].Replace("\t", "    ");​
 191:        :                 result += line.ToString(CultureInfo.InvariantCulture)​
 192:        :                     .PadLeft(4, ' ') + ": " + sourceLine.TrimEnd(' ', '\t');​
 193:        :                 if (line < upperBound) result += Environment.NewLine;​
 194:        :             }​
 195:        :             return result;​
 196:        :         }​
 197:        :     }​
 198:        : }​

Module.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : using System.IO;​
  24:        : using System.Linq;​
  25:        : 
  26:        : using Mono.Cecil;​
  27:        : using Mono.Cecil.Cil;​
  28:        : using Mono.Cecil.Mdb;​
  29:        : using Mono.Cecil.Pdb;​
  30:        : using Mono.Collections.Generic;​
  31:        : 
  32:        : namespace NinjaTurtles​
  33:        : {​
  34:        :     /// <summary>​
  35:        :     /// Class representing the main module of a .NET assembly.​
  36:        :     /// </summary>​
  37:        :     public class Module​
  38:        :     {​
  39:        :         /// <summary>​
  40:        :         /// Initializes a new instance of the <see cref="Module" /> class.​
  41:        :         /// </summary>​
  42:        :         /// <param name="assemblyLocation">​
  43:        :         /// The location on disk of the assembly whose main module is to be​
  44:        :         /// loaded.​
  45:        :         /// </param>​
  46:        :         public Module(string assemblyLocation)​
  47:        :         {​
  48:        :             AssemblyLocation = assemblyLocation;​
  49:        :             AssemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyLocation);​
  50:        :             Definition = AssemblyDefinition.MainModule;​
  51:        :             SourceFiles = new Dictionary<string, string[]>();​
  52:        :         }​
  53:        : 
  54:        :         /// <summary>​
  55:        :         /// Gets the location on disk of the assembly.​
  56:        :         /// </summary>​
  57:        :         public string AssemblyLocation { get; private set; }​
  58:        : 
  59:        :         /// <summary>​
  60:        :         /// Gets the <see cref="AssemblyDefinition" />.​
  61:        :         /// </summary>​
  62:        :         public AssemblyDefinition AssemblyDefinition { get; private set; }​
  63:        : 
  64:        :         /// <summary>​
  65:        :         /// Gets the <see cref="ModuleDefinition" />.​
  66:        :         /// </summary>​
  67:        :         public ModuleDefinition Definition { get; private set; }​
  68:        : 
  69:        :         /// <summary>​
  70:        :         /// Gets a dictionary of source code files with their contained lines​
  71:        :         /// of code.​
  72:        :         /// </summary>​
  73:        :         public IDictionary<string, string[]> SourceFiles { get; private set; } ​
  74:        : 
  75:        :         internal void LoadDebugInformation()​
  76:        :         {​
  77:     1/1:             var reader = ResolveSymbolReader();​
  78:     6/6:             if (reader == null) return;​
  79:        : 
  80:     1/1:             Definition.ReadSymbols(reader);​
  81:        : 
  82:     1/1:             LoadSourceCodeForTypes(Definition.Types, reader);​
  83:        : 
  84:   19/19:             foreach (var method in Definition.Types​
  85:     8/8:                 .SelectMany(t => t.Methods)​
  86:     8/8:                 .Where(m => m.HasBody))​
  87:        :             {​
  88:     1/1:                 MethodDefinition capturedMethod = method;​
  89:     1/1:                 reader.Read(capturedMethod.Body,​
  90:     1/1:                     o => capturedMethod.Body.Instructions.FirstOrDefault(i => i.Offset >= o));​
  91:        : 
  92:     7/7:                 var sourceFiles = method.Body.Instructions.Where(i => i.SequencePoint != null)​
  93:     7/7:                     .Select(i => i.SequencePoint.Document.Url)​
  94:     7/7:                     .Distinct();​
  95:   12/12:                 foreach (var sourceFile in sourceFiles)​
  96:        :                 {​
  97:     8/8:                     if (!SourceFiles.ContainsKey(sourceFile) && File.Exists(sourceFile))​
  98:        :                     {​
  99:     1/1:                         SourceFiles.Add(sourceFile, File.ReadAllLines(sourceFile));​
 100:        :                     }​
 101:        :                 }​
 102:        :             }​
 103:        :         }​
 104:        : 
 105:        :         private void LoadSourceCodeForTypes(Collection<TypeDefinition> types, ISymbolReader reader)​
 106:        :         {​
 107:        :             foreach (var typeDefinition in types)​
 108:        :             {​
 109:        :                 foreach (var method in typeDefinition.Methods.Where(m => m.HasBody))​
 110:        :                 {​
 111:        :                     MethodDefinition capturedMethod = method;​
 112:        :                     reader.Read(capturedMethod.Body,​
 113:        :                         o => capturedMethod.Body.Instructions.FirstOrDefault(i => i.Offset >= o));​
 114:        : 
 115:        :                     var sourceFiles = method.Body.Instructions.Where(i => i.SequencePoint != null)​
 116:        :                         .Select(i => i.SequencePoint.Document.Url)​
 117:        :                         .Distinct();​
 118:        :                     foreach (var sourceFile in sourceFiles)​
 119:        :                     {​
 120:        :                         if (!SourceFiles.ContainsKey(sourceFile) && File.Exists(sourceFile))​
 121:        :                         {​
 122:        :                             SourceFiles.Add(sourceFile, File.ReadAllLines(sourceFile));​
 123:        :                         }​
 124:        :                     }​
 125:        :                 }​
 126:        :                 if (typeDefinition.NestedTypes != null)​
 127:        :                 {​
 128:        :                     LoadSourceCodeForTypes(typeDefinition.NestedTypes, reader);​
 129:        :                 }​
 130:        :             }​
 131:        :         }​
 132:        : 
 133:        :         private ISymbolReader ResolveSymbolReader()​
 134:        :         {​
 135:        :             string symbolLocation = null;​
 136:        :             string pdbLocation = Path.ChangeExtension(AssemblyLocation, "pdb");​
 137:        :             string mdbLocation = AssemblyLocation + ".mdb";​
 138:        :             ISymbolReaderProvider provider = null;​
 139:        :             if (File.Exists(pdbLocation))​
 140:        :             {​
 141:        :                 symbolLocation = pdbLocation;​
 142:        :                 provider = new PdbReaderProvider();​
 143:        :             }​
 144:        :             else if (File.Exists(mdbLocation))​
 145:        :             {​
 146:        :                 symbolLocation = AssemblyLocation;​
 147:        :                 provider = new MdbReaderProvider();​
 148:        :             }​
 149:        :             if (provider == null) return null;​
 150:        :             var reader = provider.GetSymbolReader(Definition, symbolLocation);​
 151:        :             return reader;​
 152:        :         }​
 153:        :     }​
 154:        : }​

MutationTest.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Diagnostics;​
  25:        : using System.IO;​
  26:        : using System.Linq;​
  27:        : using System.Management;​
  28:        : using System.Text.RegularExpressions;​
  29:        : using System.Threading;​
  30:        : using System.Threading.Tasks;​
  31:        : using System.Xml.Serialization;​
  32:        : 
  33:        : using Microsoft.Win32;​
  34:        : 
  35:        : using Mono.Cecil;​
  36:        : using Mono.Cecil.Cil;​
  37:        : using Mono.Collections.Generic;​
  38:        : 
  39:        : using NinjaTurtles.Reporting;​
  40:        : using NinjaTurtles.TestRunners;​
  41:        : using NinjaTurtles.Turtles;​
  42:        : 
  43:        : namespace NinjaTurtles​
  44:        : {​
  45:        :     internal class MutationTest : IMutationTest​
  46:        :     {​
  47:        :         private const string ERROR_REPORTING_KEY = @"SOFTWARE\Microsoft\Windows\Windows Error Reporting";​
  48:        :         private const string ERROR_REPORTING_VALUE = "DontShowUI";​
  49:        : 
  50:        :         private readonly IList<Type> _mutationsToApply = new List<Type>();​
  51:        :         private readonly string _testAssemblyLocation;​
  52:        :         private readonly Type[] _parameterTypes;​
  53:        :         private readonly AssemblyDefinition _testAssembly;​
  54:        :         private readonly TypeReference _targetTypeReference;​
  55:        :         private Module _module;​
  56:        :         private IEnumerable<string> _testsToRun;​
  57:        :         private ITestRunner _runner;​
  58:        :         private MutationTestingReport _report;​
  59:        :         private ReportingStrategy _reportingStrategy = new NullReportingStrategy();​
  60:        :         private string _reportFileName;​
  61:        :         private MethodReferenceComparer _comparer;​
  62:        :         private static Regex _automaticallyGeneratedNestedClassMatcher = new Regex("^\\<([A-Za-z0-9@_]+)\\>");​
  63:        :         //private TimeSpan _benchmark;​
  64:        : 
  65:        :         internal MutationTest(string testAssemblyLocation, Type targetType, string targetMethod, Type[] parameterTypes)​
  66:        :         {​
  67:        :             TargetType = targetType;​
  68:        :             TargetMethod = targetMethod;​
  69:        :             _testAssemblyLocation = testAssemblyLocation;​
  70:        :             _parameterTypes = parameterTypes;​
  71:        :             _testAssembly = AssemblyDefinition.ReadAssembly(testAssemblyLocation);​
  72:        :             _targetTypeReference = _testAssembly.MainModule.Import(targetType);​
  73:        :         }​
  74:        : 
  75:        :         public Type TargetType { get; private set; }​
  76:        : 
  77:        :         public string TargetMethod { get; private set; }​
  78:        : 
  79:        :         public void Run()​
  80:        :         {​
  81:     1/1:             var key = Registry.LocalMachine.OpenSubKey(ERROR_REPORTING_KEY, RegistryKeyPermissionCheck.ReadWriteSubTree);​
  82:     1/1:             var errorReportingValue = key.GetValue(ERROR_REPORTING_VALUE, null);​
  83:     1/1:             key.SetValue(ERROR_REPORTING_VALUE, 1, RegistryValueKind.DWord);​
  84:     1/1:             key.Close();​
  85:        : 
  86:     1/1:             MethodDefinition method = ValidateMethod();​
  87:     1/1:             _module.LoadDebugInformation();​
  88:        : 
  89:     1/1:             _comparer = new MethodReferenceComparer();​
  90:     1/1:             var matchingMethods = new List<MethodReference>();​
  91:     1/1:             AddMethod(method, matchingMethods);​
  92:        : 
  93:     4/4:             int[] originalOffsets = method.Body.Instructions.Select(i => i.Offset).ToArray();​
  94:     1/1:             _report = new MutationTestingReport();​
  95:     1/1:             _testsToRun = GetMatchingTestsFromTree(method, matchingMethods);​
  96:        : 
  97:        :             //_benchmark = BenchmarkTestSuite();​
  98:        : 
  99:     1/1:             int count = 0;​
 100:     1/1:             int failures = 0;​
 101:     6/6:             if (_mutationsToApply.Count == 0) PopulateDefaultTurtles();​
 102:   13/13:             foreach (var turtleType in _mutationsToApply)​
 103:        :             {​
 104:     1/1:                 var turtle = (MethodTurtleBase)Activator.CreateInstance(turtleType);​
 105:     1/1:                 Parallel.ForEach(turtle.Mutate(method, _module, originalOffsets),​
 106:     1/1:                     mutation => RunMutation(turtle, mutation, ref failures, ref count));​
 107:        :             }​
 108:        : 
 109:     1/1:             _report.RegisterMethod(method);​
 110:     1/1:             _reportingStrategy.WriteReport(_report, _reportFileName);​
 111:        : 
 112:     1/1:             key = Registry.LocalMachine.OpenSubKey(ERROR_REPORTING_KEY, RegistryKeyPermissionCheck.ReadWriteSubTree);​
 113:     5/5:             if (errorReportingValue == null)​
 114:        :             {​
 115:     1/1:                 key.DeleteValue(ERROR_REPORTING_VALUE);​
 116:     1/1:             }​
 117:        :             else​
 118:        :             {​
 119:     1/1:                 key.SetValue(ERROR_REPORTING_VALUE, errorReportingValue, RegistryValueKind.DWord);​
 120:        :             }​
 121:     1/1:             key.Close();​
 122:        : 
 123:     5/5:             if (count == 0)​
 124:        :             {​
 125:     1/1:                 Console.WriteLine("No valid mutations found (this is fine).");​
 126:     1/1:                 return;​
 127:        :             }​
 128:     6/6:             if (failures > 0)​
 129:        :             {​
 130:     1/1:                 throw new MutationTestFailureException();​
 131:        :             }​
 132:        :         }​
 133:        : 
 134:        :         private void AddMethod(MethodDefinition targetMethod, List<MethodReference> matchingMethods)​
 135:        :         {​
 136:        :             if (matchingMethods.Contains(targetMethod, _comparer)) return;​
 137:        :             matchingMethods.Add(targetMethod);​
 138:        :             AddCallingMethods(targetMethod, matchingMethods);​
 139:        :             var declaringType = targetMethod.DeclaringType;​
 140:        :             TypeDefinition type = declaringType;​
 141:        :             while (type != null && type.BaseType != null)​
 142:        :             {​
 143:        :                 var thisModule = type.BaseType.Module;​
 144:        :                 if (type.BaseType.Scope.Name != type.BaseType.Module.Assembly.Name.Name​
 145:        :                     && type.BaseType.Scope is AssemblyNameReference)​
 146:        :                 {​
 147:        :                     thisModule =​
 148:        :                         type.BaseType.Module.AssemblyResolver.Resolve((AssemblyNameReference)type.BaseType.Scope).​
 149:        :                             MainModule;​
 150:        :                 }​
 151:        :                 type = thisModule.Types.SingleOrDefault(t => t.FullName == type.BaseType.FullName);​
 152:        :                 if (type != null)​
 153:        :                 {​
 154:        :                     var baseMethod = type.Methods​
 155:        :                         .SingleOrDefault(m => MethodsMatch(m, targetMethod));​
 156:        :                     if (baseMethod != null)​
 157:        :                     {​
 158:        :                         AddMethod(baseMethod, matchingMethods);​
 159:        :                         break;​
 160:        :                     }​
 161:        :                     AddMethodsForInterfaces(targetMethod, matchingMethods, type);​
 162:        :                 }​
 163:        :             }​
 164:        :             AddMethodsForInterfaces(targetMethod, matchingMethods, declaringType);​
 165:        :         }​
 166:        : 
 167:        :         private void AddMethodsForInterfaces(MethodDefinition targetMethod, List<MethodReference> matchingMethods, TypeDefinition type)​
 168:        :         {​
 169:        :             foreach (var interfaceReference in type.Interfaces)​
 170:        :             {​
 171:        :                 var thisModule = type.Module;​
 172:        :                 if (interfaceReference.Scope.Name != type.Module.Assembly.Name.Name​
 173:        :                     && interfaceReference.Scope is AssemblyNameReference)​
 174:        :                 {​
 175:        :                     thisModule =​
 176:        :                         interfaceReference.Module.AssemblyResolver.Resolve((AssemblyNameReference)interfaceReference.Scope).​
 177:        :                             MainModule;​
 178:        :                 }​
 179:        :                 var interfaceDefinition =​
 180:        :                     thisModule.Types.SingleOrDefault(t => t.FullName == interfaceReference.FullName);​
 181:        :                 if (interfaceDefinition != null)​
 182:        :                 {​
 183:        :                     var interfaceMethod = interfaceDefinition.Methods​
 184:        :                         .SingleOrDefault(m => MethodsMatch(m, targetMethod));​
 185:        :                     if (interfaceMethod != null)​
 186:        :                     {​
 187:        :                         AddMethod(interfaceMethod, matchingMethods);​
 188:        :                     }​
 189:        :                 }​
 190:        :             }​
 191:        :         }​
 192:        : 
 193:        :         private bool MethodsMatch(MethodDefinition first, MethodDefinition second)​
 194:        :         {​
 195:   18/18:             return first.Name == second.Name​
 196:   18/18:                    && Enumerable.SequenceEqual(first.Parameters.Select(p => p.ParameterType.Name),​
 197:   18/18:                                                second.Parameters.Select(p => p.ParameterType.Name))​
 198:   18/18:                    && first.GenericParameters.Count == second.GenericParameters.Count;​
 199:        :         }​
 200:        : 
 201:        :         private ISet<string> GetMatchingTestsFromTree(MethodDefinition targetmethod, IList<MethodReference> matchingMethods, bool force = false)​
 202:        :         {​
 203:     1/1:             ISet<string> result = new HashSet<string>();​
 204:   10/10:             foreach (var type in _testAssembly.MainModule.Types)​
 205:     2/2:             AddTestsForType(targetmethod, matchingMethods, force, type, result);​
 206:   10/10:             if (!force && result.Count == 0)​
 207:        :             {​
 208:     1/1:                 result = GetMatchingTestsFromTree(targetmethod, matchingMethods, true);​
 209:        :             }​
 210:     6/6:             if (result.Count == 0)​
 211:        :             {​
 212:     1/1:                 throw new MutationTestFailureException(​
 213:     1/1:                     "No matching tests were found to run.");​
 214:        :             }​
 215:        :             return result;​
 216:        :         }​
 217:        : 
 218:        :         private void AddTestsForType(MethodDefinition targetmethod, IList<MethodReference> matchingMethods, bool force, TypeDefinition type,​
 219:        :                                      ISet<string> result)​
 220:        :         {​
 221:        :             foreach (var method in type.Methods.Where(m => m.HasBody))​
 222:        :             {​
 223:        :                 var targetType = targetmethod.DeclaringType.FullName;​
 224:        :                 if (!force && !DoesMethodReferenceType(method, targetType)) continue;​
 225:        :                 foreach (var instruction in method.Body.Instructions)​
 226:        :                 {​
 227:        :                     if (instruction.OpCode == OpCodes.Call​
 228:        :                         || instruction.OpCode == OpCodes.Callvirt​
 229:        :                         || instruction.OpCode == OpCodes.Newobj​
 230:        :                         || instruction.OpCode == OpCodes.Ldftn)​
 231:        :                     {​
 232:        :                         var reference = (MethodReference)instruction.Operand;​
 233:        :                         if (matchingMethods.Any(m => _comparer.Equals(m, reference))​
 234:        :                             && !method.CustomAttributes.Any(a => a.AttributeType.Name == "MutationTestAttribute"))​
 235:        :                         {​
 236:        :                             result.Add(string.Format("{0}.{1}", type.FullName.Replace("/", "+"), method.Name));​
 237:        :                             break;​
 238:        :                         }​
 239:        :                     }​
 240:        :                 }​
 241:        :             }​
 242:        :             if (type.NestedTypes != null)​
 243:        :             {​
 244:        :                 foreach (var typeDefinition in type.NestedTypes)​
 245:        :                 {​
 246:        :                     AddTestsForType(targetmethod, matchingMethods, force, typeDefinition, result);​
 247:        :                 }​
 248:        :             }​
 249:        :         }​
 250:        : 
 251:        :         private static bool DoesMethodReferenceType(MethodDefinition method, string targetType)​
 252:        :         {​
 253:     1/1:             bool typeUsed = false;​
 254:   13/13:             foreach (var instruction in method.Body.Instructions)​
 255:        :             {​
 256:   16/16:                 if (instruction.OpCode == OpCodes.Call​
 257:   16/16:                     || instruction.OpCode == OpCodes.Callvirt​
 258:   16/16:                     || instruction.OpCode == OpCodes.Newobj​
 259:   16/16:                     || instruction.OpCode == OpCodes.Ldftn)​
 260:        :                 {​
 261:     1/1:                     var reference = (MethodReference)instruction.Operand;​
 262:     1/1:                     var declaringType = reference.DeclaringType;​
 263:     9/9:                     if (declaringType.FullName == targetType)​
 264:        :                     {​
 265:     3/3:                         typeUsed = true;​
 266:     1/1:                         break;​
 267:        :                     }​
 268:     1/1:                     var genericType = declaringType as GenericInstanceType;​
 269:     9/9:                     if (genericType != null)​
 270:        :                     {​
 271:   12/12:                         if (genericType.GenericArguments.Any(a => a.FullName == targetType))​
 272:        :                         {​
 273:     3/3:                             typeUsed = true;​
 274:     1/1:                             break;​
 275:        :                         }​
 276:        :                     }​
 277:     1/1:                     var genericMethod = reference as GenericInstanceMethod;​
 278:     9/9:                     if (genericMethod != null)​
 279:        :                     {​
 280:   12/12:                         if (genericMethod.GenericArguments.Any(a => a.FullName == targetType))​
 281:        :                         {​
 282:     3/3:                             typeUsed = true;​
 283:     1/1:                             break;​
 284:        :                         }​
 285:        :                     }​
 286:        :                 }​
 287:     9/9:                 if (instruction.OpCode == OpCodes.Newobj)​
 288:        :                 {​
 289:     1/1:                     var constructor = (MemberReference)instruction.Operand;​
 290:     1/1:                     var declaringType = constructor.DeclaringType;​
 291:     9/9:                     if (declaringType.FullName == targetType)​
 292:        :                     {​
 293:     3/3:                         typeUsed = true;​
 294:     1/1:                         break;​
 295:        :                     }​
 296:        :                 }​
 297:        :             }​
 298:     4/4:             return typeUsed;​
 299:        :         }​
 300:        : 
 301:        :         private void AddCallingMethods(MethodReference targetMethod, List<MethodReference> matchingMethods)​
 302:        :         {​
 303:     9/9:             foreach (var type in _module.Definition.Types)​
 304:     1/1:             AddCallingMethodsForType(targetMethod, matchingMethods, type);​
 305:        :         }​
 306:        : 
 307:        :         private void AddCallingMethodsForType(MethodReference targetMethod, List<MethodReference> matchingMethods, TypeDefinition type)​
 308:        :         {​
 309:   16/16:             foreach (var method in type.Methods.Where(m => m.HasBody))​
 310:     9/9:             foreach (var instruction in method.Body.Instructions)​
 311:        :             {​
 312:   14/14:                 if (instruction.OpCode == OpCodes.Call​
 313:   14/14:                     || instruction.OpCode == OpCodes.Callvirt​
 314:   14/14:                     || instruction.OpCode == OpCodes.Newobj​
 315:   14/14:                     || instruction.OpCode == OpCodes.Ldftn)​
 316:        :                 {​
 317:     1/1:                     var reference = (MethodReference)instruction.Operand;​
 318:   10/10:                     if (_comparer.Equals(reference, targetMethod)​
 319:   10/10:                         && !matchingMethods.Contains(method, _comparer))​
 320:        :                     {​
 321:     1/1:                         AddMethod(method, matchingMethods);​
 322:     2/2:                         var match = _automaticallyGeneratedNestedClassMatcher.Match(type.Name);​
 323:     9/9:                         if (match.Success && type.DeclaringType != null)​
 324:        :                         {​
 325:     9/9:                             if (type.DeclaringType.Methods.Any(m => m.Name == match.Groups[1].Value))​
 326:        :                             {​
 327:     5/5:                                 AddMethod(type.DeclaringType.Methods.First(m => m.Name == match.Groups[1].Value), matchingMethods);​
 328:        :                             }​
 329:        :                         }​
 330:        :                     }​
 331:        :                 }​
 332:        :             }​
 333:   10/10:             foreach (var nestedType in type.NestedTypes)​
 334:        :             {​
 335:     3/3:                 AddCallingMethodsForType(targetMethod, matchingMethods, nestedType);​
 336:        :             }​
 337:        :         }​
 338:        : 
 339:        :         private class MethodReferenceComparer : IEqualityComparer<MethodReference>​
 340:        :         {​
 341:        :             public bool Equals(MethodReference x, MethodReference y)​
 342:        :             {​
 343:        :                 if (x.Name != y.Name) return false;​
 344:        :                         return x.DeclaringType.FullName == y.DeclaringType.FullName​
 345:        :                         && Enumerable.SequenceEqual(x.Parameters.Select(p => p.ParameterType.Name),​
 346:        :                                                  y.Parameters.Select(p => p.ParameterType.Name))​
 347:        :                         && x.GenericParameters.Count == y.GenericParameters.Count;​
 348:        :             }​
 349:        : 
 350:        :             public int GetHashCode(MethodReference obj)​
 351:        :             {​
 352:        :                 return obj.Name.GetHashCode();​
 353:        :             }​
 354:        :         }​
 355:        : 
 356:        :         private void RunMutation(MethodTurtleBase turtle, MutantMetaData mutation, ref int failures, ref int count)​
 357:        :         {​
 358:     2/2:             bool testProcessFailed = CheckTestProcessFails(turtle, mutation);​
 359:     8/8:             if (!testProcessFailed)​
 360:        :             {​
 361:     1/1:                 Interlocked.Increment(ref failures);​
 362:        :             }​
 363:     1/1:             Interlocked.Increment(ref count);​
 364:        :         }​
 365:        : 
 366:        : //        private TimeSpan BenchmarkTestSuite()​
 367:        : //        {​
 368:        : //            var testDirectory = new TestDirectory(Path.GetDirectoryName(_testAssemblyLocation));​
 369:        : //​
 370:        : //            var process = GetTestRunnerProcess(testDirectory);​
 371:        : //​
 372:        : //            var stopwatch = new Stopwatch();​
 373:        : //            stopwatch.Start();​
 374:        : //            process.Start();​
 375:        : //            process.WaitForExit();​
 376:        : //            stopwatch.Stop();​
 377:        : //​
 378:        : //            testDirectory.Dispose();​
 379:        : //​
 380:        : //            if (process.ExitCode != 0)​
 381:        : //            {​
 382:        : //                throw new MutationTestFailureException("Test suite does not pass with unmutated code - mutation testing aborted.");​
 383:        : //            }​
 384:        : //            var timespan = stopwatch.Elapsed;​
 385:        : //            Console.WriteLine("Test suite benchmarked at {0:0.000} seconds.", timespan.TotalSeconds);​
 386:        : //​
 387:        : //            return timespan;​
 388:        : //        }​
 389:        : 
 390:        :         private Process GetTestRunnerProcess(TestDirectory testDirectory)​
 391:        :         {​
 392:        :             if (_runner == null) _runner = (ITestRunner)Activator.CreateInstance(MutationTestBuilder.TestRunner);​
 393:        :             return _runner.GetRunnerProcess(testDirectory, _testAssemblyLocation, _testsToRun);​
 394:        :         }​
 395:        : 
 396:        :         private bool CheckTestProcessFails(MethodTurtleBase turtle, MutantMetaData mutation)​
 397:        :         {​
 398:     1/1:             var process = GetTestRunnerProcess(mutation.TestDirectory);​
 399:        : 
 400:     1/1:             process.Start();​
 401:     4/4:             bool exitedInTime = process.WaitForExit(30000); //Math.Min(30000, (int)(5 * _benchmark.TotalMilliseconds)));​
 402:     1/1:             int exitCode = -1;​
 403:        : 
 404:        :             try​
 405:        :             {​
 406:   14/14:                 if (!exitedInTime)​
 407:        :                 {​
 408:     1/1:                     KillProcessAndChildren(process.Id);​
 409:        :                 }​
 410:     1/1:                 exitCode = process.ExitCode;​
 411:     1/1:             }​
 412:     2/2:             catch {}​
 413:        : 
 414:     7/7:             bool testSuitePassed = exitCode == 0 && exitedInTime;​
 415:        : 
 416:     7/7:             string result = string.Format("Mutant: {0}. {1}",​
 417:     7/7:                               mutation.Description,​
 418:     7/7:                               testSuitePassed​
 419:     7/7:                                   ? "Survived."​
 420:     7/7:                                 : "Killed.");​
 421:     4/4:             _report.AddResult(turtle.GetCurrentSequencePoint(mutation.ILIndex), mutation, !testSuitePassed);​
 422:        : 
 423:   14/14:             if (testSuitePassed)​
 424:        :             {​
 425:     1/1:                 mutation.TestDirectory.DoNotDelete = true;​
 426:     1/1:                 result = string.Format("{0}\nOriginal source code around surviving mutant (in {1}):\n{2}\nFiles left for inspection in: {3}",​
 427:     1/1:                     result,​
 428:     1/1:                     turtle.GetOriginalSourceFileName(mutation.ILIndex),​
 429:     1/1:                     turtle.GetOriginalSourceCode(mutation.ILIndex),​
 430:     1/1:                     mutation.TestDirectoryName);​
 431:        :             }​
 432:        : 
 433:     1/1:             Console.WriteLine(result);​
 434:        : 
 435:     1/1:             turtle.MutantComplete(mutation);​
 436:     6/6:             return !testSuitePassed;​
 437:        :         }​
 438:        : 
 439:        :         private void KillProcessAndChildren(int pid)​
 440:        :         {​
 441:        :             using (var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid))​
 442:        :             using (ManagementObjectCollection moc = searcher.Get())​
 443:        :             {​
 444:        :                 foreach (ManagementObject mo in moc)​
 445:        :                 {​
 446:        :                     KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));​
 447:        :                 }​
 448:        :                 try​
 449:        :                 {​
 450:        :                     Process proc = Process.GetProcessById(pid);​
 451:        :                     proc.Kill();​
 452:        :                 }​
 453:        :                 catch (ArgumentException) {}​
 454:        :             }​
 455:        :         }​
 456:        : 
 457:        : 
 458:        :         private void PopulateDefaultTurtles()​
 459:        :         {​
 460:        :             foreach (var type in GetType().Assembly.GetTypes()​
 461:        :                 .Where(t => t.GetInterface("IMethodTurtle") != null​
 462:        :                 && !t.IsAbstract))​
 463:        :             {​
 464:        :                 _mutationsToApply.Add(type);​
 465:        :             }​
 466:        :         }​
 467:        : 
 468:        :         private MethodDefinition ValidateMethod()​
 469:        :         {​
 470:        :             _module = new Module(TargetType.Assembly.Location);​
 471:        : 
 472:        :             var type = ResolveFromTypeCollection(_module.Definition.Types);​
 473:        :             return MethodDefinitionResolver.ResolveMethod(type, TargetMethod, _parameterTypes);​
 474:        :         }​
 475:        : 
 476:        :         private TypeDefinition ResolveFromTypeCollection(Collection<TypeDefinition> types)​
 477:        :         {​
 478:        :             var type = types.SingleOrDefault(t => t.FullName == TargetType.FullName.Replace("+", "/"));​
 479:        :             if (type == null)​
 480:        :             {​
 481:        :                 foreach (var typeDefinition in types)​
 482:        :                 {​
 483:        :                     if (typeDefinition.NestedTypes != null)​
 484:        :                     {​
 485:        :                         type = ResolveFromTypeCollection(typeDefinition.NestedTypes);​
 486:        :                         if (type != null) return type;​
 487:        :                     }​
 488:        :                 }​
 489:        :             }​
 490:        :             return type;​
 491:        :         }​
 492:        : 
 493:        :         public IMutationTest With<T>() where T : IMethodTurtle​
 494:        :         {​
 495:        :             _mutationsToApply.Add(typeof(T));​
 496:        :             return this;​
 497:        :         }​
 498:        : 
 499:        :         /// <summary>​
 500:        :         /// Sets the unit test runner to be used, which is an implementation of​
 501:        :         /// <see cref="ITestRunner" />. If none is specified, then the default​
 502:        :         /// is to use <see cref="NUnitTestRunner" />.​
 503:        :         /// </summary>​
 504:        :         /// <typeparam name="T">​
 505:        :         /// A type that implements <see cref="ITestRunner" />.​
 506:        :         /// </typeparam>​
 507:        :         /// <returns>​
 508:        :         /// The original <see cref="IMutationTest" /> instance to allow fluent​
 509:        :         /// method chaining.​
 510:        :         /// </returns>​
 511:        :         public IMutationTest UsingRunner<T>() where T : ITestRunner, new()​
 512:        :         {​
 513:        :             _runner = new T();​
 514:        :             return this;​
 515:        :         }​
 516:        : 
 517:        :         public IMutationTest WriteReportTo(string fileName)​
 518:        :         {​
 519:        :             _reportingStrategy = new OverwriteReportingStrategy();​
 520:        :             _reportFileName = fileName;​
 521:        :             return this;​
 522:        :         }​
 523:        : 
 524:        :         public IMutationTest MergeReportTo(string fileName)​
 525:        :         {​
 526:        :             _reportingStrategy = new MergeReportingStrategy();​
 527:        :             _reportFileName = fileName;​
 528:        :             return this;​
 529:        :         }​
 530:        : 
 531:        :         private abstract class ReportingStrategy​
 532:        :         {​
 533:        :             public abstract void WriteReport(MutationTestingReport report, string fileName);​
 534:        :         }​
 535:        : 
 536:        :         private class NullReportingStrategy : ReportingStrategy​
 537:        :         {​
 538:        :             public override void WriteReport(MutationTestingReport report, string fileName) { }​
 539:        :         }​
 540:        : 
 541:        :         private class OverwriteReportingStrategy : ReportingStrategy​
 542:        :         {​
 543:        :             public override void WriteReport(MutationTestingReport report, string fileName)​
 544:        :             {​
 545:        :                 using (var streamWriter = File.CreateText(fileName))​
 546:        :                 {​
 547:        :                     new XmlSerializer(typeof(MutationTestingReport)).Serialize(streamWriter, report);​
 548:        :                 }​
 549:        :             }​
 550:        :         }​
 551:        : 
 552:        :         private class MergeReportingStrategy : ReportingStrategy​
 553:        :         {​
 554:        :             public override void WriteReport(MutationTestingReport report, string fileName)​
 555:        :             {​
 556:        :                 report.MergeFromFile(fileName);​
 557:        :                 using (var streamWriter = File.CreateText(fileName))​
 558:        :                 {​
 559:        :                     new XmlSerializer(typeof(MutationTestingReport)).Serialize(streamWriter, report);​
 560:        :                 }​
 561:        :             }​
 562:        :         }​
 563:        :     }​
 564:        : }​
 565:        : 

MutationTestBuilder.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Reflection;​
  24:        : 
  25:        : using NinjaTurtles.TestRunners;​
  26:        : 
  27:        : namespace NinjaTurtles​
  28:        : {​
  29:        :     /// <summary>​
  30:        :     /// A static class used as the starting point for a fluent definition of​
  31:        :     /// a set of mutation tests.​
  32:        :     /// </summary>​
  33:        :     /// <typeparam name="T">​
  34:        :     /// The type to be tested.​
  35:        :     /// </typeparam>​
  36:        :     /// <example>​
  37:        :     /// <para>​
  38:        :     /// This code creates and runs mutation tests for the ​
  39:        :     /// <b>ClassUnderTest</b> class's <b>MethodUnderTest</b> method:​
  40:        :     /// </para>​
  41:        :     /// <code lang="cs">​
  42:        :     /// MutationTestBuilder&lt;ClassUnderTest&gt;​
  43:        :     ///     .For("MethodUnderTest")​
  44:        :     ///     .Run();​
  45:        :     /// </code>​
  46:        :     /// <code lang="vbnet">​
  47:        :     /// Call MutationTestBuilder(Of ClassUnderTest) _​
  48:        :     ///     .For("MethodUnderTest") _​
  49:        :     ///     .Run​
  50:        :     /// </code>​
  51:        :     /// <code lang="cpp">​
  52:        :     /// MutationTestBuilder&lt;ClassUnderTest^&gt;​
  53:        :     ///     ::For("MethodUnderTest")​
  54:        :     ///     ->Run();​
  55:        :     /// </code>​
  56:        :     /// <para>​
  57:        :     /// When this code is included in a test, it causes the matching tests to​
  58:        :     /// be run for each mutation that is found of the code under test. The​
  59:        :     /// matching tests are determined automatically by NinjaTurtles. By​
  60:        :     /// default, NinjaTurtles assumes it is running under NUnit, and thus uses​
  61:        :     /// an NUnit runner to run the suite against the mutated code. This can be​
  62:        :     /// changed using the fluent interface:​
  63:        :     /// </para>​
  64:        :     /// <code lang="cs">​
  65:        :     /// MutationTestBuilder&lt;ClassUnderTest&gt;​
  66:        :     ///     .For("MethodUnderTest")​
  67:        :     ///     .UsingRunner&lt;GallioTestRunner&gt;()​
  68:        :     ///     .Run();​
  69:        :     /// </code>​
  70:        :     /// <code lang="vbnet">​
  71:        :     /// Call MutationTestBuilder(Of ClassUnderTest) _​
  72:        :     ///     .For("MethodUnderTest") _​
  73:        :     ///     .UsingRunner(Of GallioTestRunner)() _​
  74:        :     ///     .Run​
  75:        :     /// </code>​
  76:        :     /// <code lang="cpp">​
  77:        :     /// MutationTestBuilder&lt;ClassUnderTest^&gt;​
  78:        :     ///     ::For("MethodUnderTest")​
  79:        :     ///     ->UsingRunner&lt;GallioTestRunner^&gt;()​
  80:        :     ///     ->Run();​
  81:        :     /// </code>​
  82:        :     /// <para>​
  83:        :     /// Alternatively, this option can be set across all tests in a fixture by​
  84:        :     /// including this line in the test fixture's setup method:​
  85:        :     /// </para>​
  86:        :     /// <code lang="cs">​
  87:        :     /// MutationTestBuilder.UseRunner&lt;GallioTestRunner&gt;();​
  88:        :     /// </code>​
  89:        :     /// <code lang="vbnet">​
  90:        :     /// Call MutationTestBuilder.UseRunner(Of GallioTestRunner)​
  91:        :     /// </code>​
  92:        :     /// <code lang="cpp">​
  93:        :     /// MutationTestBuilder::UseRunner&lt;GallioTestRunner^&gt;();​
  94:        :     /// </code>​
  95:        :     /// </example>​
  96:        :     public sealed class MutationTestBuilder<T>​
  97:        :     {​
  98:        :         /// <summary>​
  99:        :         /// Returns an <see cref="IMutationTest" /> instance allowing a fluent​
 100:        :         /// definition of a set of mutation tests for a particular method.​
 101:        :         /// </summary>​
 102:        :         /// <param name="targetMethod">​
 103:        :         /// The name of the method to mutate.​
 104:        :         /// </param>​
 105:        :         /// <param name="parameterTypes">​
 106:        :         /// Optional parameter specifying an array of parameter types used to​
 107:        :         /// identify a particular method overload.​
 108:        :         /// </param>​
 109:        :         /// <returns>​
 110:        :         /// An <see cref="IMutationTest" /> instance to allow fluent​
 111:        :         /// method chaining.​
 112:        :         /// </returns>​
 113:        :         public static IMutationTest For(string targetMethod, Type[] parameterTypes = null)​
 114:        :         {​
 115:        :             var callingAssembly = Assembly.GetCallingAssembly();​
 116:        :             return MutationTestBuilder.For(callingAssembly.Location, typeof(T), targetMethod, parameterTypes);​
 117:        :         }​
 118:        :     }​
 119:        : 
 120:        :     /// <summary>​
 121:        :     /// A static class used as the starting point for a fluent definition of​
 122:        :     /// a set of mutation tests.​
 123:        :     /// </summary>​
 124:        :     /// <remarks>​
 125:        :     /// For public classes, the generic <see cref="MutationTestBuilder{T}" />​
 126:        :     /// is to be prefered. See that class for full documentation.​
 127:        :     /// </remarks>​
 128:        :     public sealed class MutationTestBuilder​
 129:        :     {​
 130:        :         internal static Type TestRunner { get; set; }​
 131:        : 
 132:        :         static MutationTestBuilder()​
 133:        :         {​
 134:        :             TestRunner = typeof(NUnitTestRunner);​
 135:        :         }​
 136:        : 
 137:        :         /// <summary>​
 138:        :         /// Returns an <see cref="IMutationTest" /> instance allowing a fluent​
 139:        :         /// definition of a set of mutation tests for a particular method.​
 140:        :         /// </summary>​
 141:        :         /// <param name="targetClass">​
 142:        :         /// The namespace-qualified name of the type for which mutation tests​
 143:        :         /// are being defined.​
 144:        :         /// </param>​
 145:        :         /// <param name="targetMethod">​
 146:        :         /// The name of the method to mutate.​
 147:        :         /// </param>​
 148:        :         /// <param name="parameterTypes">​
 149:        :         /// Optional parameter specifying an array of parameter types used to​
 150:        :         /// identify a particular method overload.​
 151:        :         /// </param>​
 152:        :         /// <returns>​
 153:        :         /// An <see cref="IMutationTest" /> instance to allow fluent​
 154:        :         /// method chaining.​
 155:        :         /// </returns>​
 156:        :         public static IMutationTest For(string targetClass, string targetMethod, Type[] parameterTypes = null)​
 157:        :         {​
 158:     1/1:             var callingAssembly = Assembly.GetCallingAssembly();​
 159:     2/2:             Type resolvedType = TypeResolver.ResolveTypeFromReferences(callingAssembly, targetClass);​
 160:        : 
 161:     1/1:             return For(callingAssembly.Location, resolvedType, targetMethod, parameterTypes);​
 162:        :         }​
 163:        : 
 164:        :         internal static IMutationTest For(string callingAssemblyLocation, Type targetType, string targetMethod, Type[] parameterTypes)​
 165:        :         {​
 166:        :             return new MutationTest(callingAssemblyLocation, targetType, targetMethod, parameterTypes);​
 167:        :         }​
 168:        : 
 169:        :         /// <summary>​
 170:        :         /// Specifies the implementation of <see cref="ITestRunner" /> to be​
 171:        :         /// used to run the test suite for each mutant. By default, this will​
 172:        :         /// be the <see cref="NUnitTestRunner" />. This can still be overridden​
 173:        :         /// on a per-test basis using the​
 174:        :         /// <see mref="IMutationTest.UsingRunner" /> method.​
 175:        :         /// </summary>​
 176:        :         /// <typeparam name="T">​
 177:        :         /// A type that implements <see cref="ITestRunner" />.​
 178:        :         /// </typeparam>​
 179:        :         public static void UseRunner<T>() where T : ITestRunner​
 180:        :         {​
 181:        :             TestRunner = typeof(T);​
 182:        :         }​
 183:        :     }​
 184:        : }​
 185:        : 

OpCodeRotationTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : 
  24:        : using Mono.Cecil;​
  25:        : using Mono.Cecil.Cil;​
  26:        : 
  27:        : namespace NinjaTurtles.Turtles​
  28:        : {​
  29:        :     /// <summary>​
  30:        :     /// An abstract base class for implementations of​
  31:        :     /// <see cref="IMethodTurtle" /> that operator by replacing a number of​
  32:        :     /// IL OpCodes with a list of replacements in turn.​
  33:        :     /// </summary>​
  34:        :     /// <remarks>​
  35:        :     /// Classes extending this one only need to set the value of the​
  36:        :     /// <see fref="_opCodes" /> field to an appropriate dictionary of source​
  37:        :     /// and target OpCodes.​
  38:        :     /// </remarks>​
  39:        :     public abstract class OpCodeRotationTurtle : MethodTurtleBase​
  40:        :     {​
  41:        :         /// <summary>​
  42:        :         /// An <see cref="IDictionary{K,V}" /> containing source OpCodes as​
  43:        :         /// keys, and <see cref="IEnumerable{T}" />s of OpCodes as each key's​
  44:        :         /// possible replacements.​
  45:        :         /// </summary>​
  46:        :         protected IDictionary<OpCode, IEnumerable<OpCode>> _opCodes;​
  47:        : 
  48:        :         /// <summary>​
  49:        :         /// Performs the actual code mutations, returning each with​
  50:        :         /// <c>yield</c> for the calling code to use.​
  51:        :         /// </summary>​
  52:        :         /// <remarks>​
  53:        :         /// Implementing classes should yield the result obtained by calling​
  54:        :         /// the <see mref="DoYield" /> method.​
  55:        :         /// </remarks>​
  56:        :         /// <param name="method">​
  57:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  58:        :         /// testing is to be carried out.​
  59:        :         /// </param>​
  60:        :         /// <param name="module">​
  61:        :         /// A <see cref="Module" /> representing the main module of the​
  62:        :         /// containing assembly.​
  63:        :         /// </param>​
  64:        :         /// <returns>​
  65:        :         /// An <see cref="IEnumerable{T}" /> of​
  66:        :         /// <see cref="MutantMetaData" /> structures.​
  67:        :         /// </returns>​
  68:        :         protected override IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module)​
  69:        :         {​
  70:   16/16:             for (int index = 0; index < method.Body.Instructions.Count; index++)​
  71:        :             {​
  72:     2/2:                 var instruction = method.Body.Instructions[index];​
  73:     7/7:                 if (_opCodes.ContainsKey(instruction.OpCode))​
  74:        :                 {​
  75:     8/8:                     if (instruction.IsMeaninglessUnconditionalBranch()) continue;​
  76:        : 
  77:     2/2:                     var originalOpCode = instruction.OpCode;​
  78:        : 
  79:   12/12:                     foreach (var opCode in _opCodes[originalOpCode])​
  80:        :                     {​
  81:     2/2:                         instruction.OpCode = opCode;​
  82:     5/5:                         var description = string.Format("{0:x4}: {1} => {2}", GetOriginalOffset(index), originalOpCode.Code, opCode.Code);​
  83:     2/2:                         MutantMetaData mutation = DoYield(method, module, description, index);​
  84:     4/4:                         yield return mutation;​
  85:        :                     }​
  86:        : 
  87:     2/2:                     instruction.OpCode = originalOpCode;​
  88:        :                 }​
  89:        :             }​
  90:        :         }​
  91:        :     }​
  92:        : }​

SequencePointDeletionTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System.Collections.Generic;​
  23:        : using System.Linq;​
  24:        : 
  25:        : using Mono.Cecil;​
  26:        : using Mono.Cecil.Cil;​
  27:        : 
  28:        : namespace NinjaTurtles.Turtles​
  29:        : {​
  30:        :     /// <summary>​
  31:        :     /// An implementation of <see cref="IMethodTurtle" /> that removes from the​
  32:        :     /// compiled IL each sequence point in turn (with the exception of​
  33:        :     /// structurally vital ones and compiler generated ones).​
  34:        :     /// </summary>​
  35:        :     public class SequencePointDeletionTurtle : MethodTurtleBase​
  36:        :     {​
  37:        :         /// <summary>​
  38:        :         /// Performs the actual code mutations, returning each with​
  39:        :         /// <c>yield</c> for the calling code to use.​
  40:        :         /// </summary>​
  41:        :         /// <remarks>​
  42:        :         /// Implementing classes should yield the result obtained by calling​
  43:        :         /// the <see mref="DoYield" /> method.​
  44:        :         /// </remarks>​
  45:        :         /// <param name="method">​
  46:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  47:        :         /// testing is to be carried out.​
  48:        :         /// </param>​
  49:        :         /// <param name="module">​
  50:        :         /// A <see cref="Module" /> representing the main module of the​
  51:        :         /// containing assembly.​
  52:        :         /// </param>​
  53:        :         /// <returns>​
  54:        :         /// An <see cref="IEnumerable{T}" /> of​
  55:        :         /// <see cref="MutantMetaData" /> structures.​
  56:        :         /// </returns>​
  57:        :         protected override IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module)​
  58:        :         {​
  59:     1/1:             var sequence = new Dictionary<int, OpCode>();​
  60:     3/3:             int startIndex = -1;​
  61:   19/19:             for (int index = 0; index < method.Body.Instructions.Count; index++)​
  62:        :             {​
  63:     3/3:                 var instruction = method.Body.Instructions[index];​
  64:   10/10:                 if (instruction.SequencePoint != null​
  65:   10/10:                     && instruction.SequencePoint.StartLine != 0xfeefee)​
  66:        :                 {​
  67:     5/5:                     startIndex = index;​
  68:     1/1:                     sequence.Clear();​
  69:        :                 }​
  70:   10/10:                 if (startIndex >= 0)​
  71:        :                 {​
  72:     3/3:                     sequence.Add(index, instruction.OpCode);​
  73:        :                 }​
  74:   12/12:                 if (index == method.Body.Instructions.Count - 1 || instruction.Next.SequencePoint != null)​
  75:        :                 {​
  76:     8/8:                     if (!ShouldDeleteSequence(method.Body, sequence)) continue;​
  77:        : 
  78:     3/3:                     OpCode originalOpCode = method.Body.Instructions[startIndex].OpCode;​
  79:     3/3:                     object originalOperand = method.Body.Instructions[startIndex].Operand;​
  80:     3/3:                     method.Body.Instructions[startIndex].OpCode = OpCodes.Br;​
  81:     3/3:                     method.Body.Instructions[startIndex].Operand = instruction.Next;​
  82:        : 
  83:     5/5:                     var codes = string.Join(", ", sequence.Values.Select(o => o.Code));​
  84:     5/5:                     var description = string.Format("{0:x4}: deleting {1}", GetOriginalOffset(startIndex), codes);​
  85:     4/4:                     MutantMetaData mutation = DoYield(method, module, description, startIndex);​
  86:     4/4:                     yield return mutation;​
  87:        : 
  88:     3/3:                     method.Body.Instructions[startIndex].OpCode = originalOpCode;​
  89:     3/3:                     method.Body.Instructions[startIndex].Operand = originalOperand;​
  90:        :                 }​
  91:        :             }​
  92:        :         }​
  93:        : 
  94:        :         private bool ShouldDeleteSequence(MethodBody method, IDictionary<int, OpCode> opCodes)​
  95:        :         {​
  96:   11/11:             if (opCodes.Values.All(o => o == OpCodes.Nop)) return false;​
  97:   11/11:             if (opCodes.Values.All(o => o == OpCodes.Pop)) return false;​
  98:   11/11:             if (opCodes.Values.All(o => o == OpCodes.Leave)) return false;​
  99:   11/11:             if (opCodes.Values.Any(o => o == OpCodes.Ret)) return false;​
 100:        : 
 101:        :             // If just setting compiler-generated return variable in Debug mode, don't delete.​
 102:     7/7:             if (opCodes.Values.Last().Code == Code.Br)​
 103:        :             {​
 104:   11/11:                 if (((Instruction)method.Instructions[opCodes.Keys.Last()].Operand).Offset​
 105:   11/11:                     == method.Instructions[opCodes.Keys.Last() + 1].Offset)​
 106:        :                 {​
 107:   11/11:                     if (method.Instructions[opCodes.Keys.Last() + 2].OpCode == OpCodes.Ret)​
 108:        :                     {​
 109:     1/1:                         return false;​
 110:        :                     }​
 111:        :                 }​
 112:        :             }​
 113:        : 
 114:        :             // If calling base constructor, don't delete.​
 115:   10/10:             if (opCodes.Any(kv => kv.Value == OpCodes.Call))​
 116:        :             {​
 117:   10/10:                 if (((MethodReference)method.Instructions[opCodes.First(kv => kv.Value == OpCodes.Call).Key].Operand).Name == Methods.CONSTRUCTOR)​
 118:        :                 {​
 119:     1/1:                     return false;​
 120:        :                 }​
 121:        :             }​
 122:        : 
 123:        :             // If compiler-generated dispose, don't delete.​
 124:     7/7:             if (method.Instructions[opCodes.Keys.First()].IsPartOfCompilerGeneratedDispose())​
 125:        :             {​
 126:     1/1:                 return false;​
 127:        :             }​
 128:        : 
 129:        :             // If setting default value to a field, don't delete.​
 130:   14/14:             if (method.Instructions[opCodes.Keys.First()]​
 131:   14/14:                 .FollowsSequence(OpCodes.Ldarg, OpCodes.Ldc_I4, OpCodes.Stfld)​
 132:   14/14:                 && (int)method.Instructions[opCodes.Keys.First() + 1].Operand == 0)​
 133:        :             {​
 134:     1/1:                 return false;​
 135:        :             }​
 136:        : 
 137:     1/1:             return true;​
 138:        :         }​
 139:        :     }​
 140:        : }​

TestDirectory.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.IO;​
  24:        : 
  25:        : using NLog;​
  26:        : 
  27:        : namespace NinjaTurtles​
  28:        : {​
  29:        :     /// <summary>​
  30:        :     /// Represents a temporary directory used to contain a mutated assembly​
  31:        :     /// to be tested. The directory cleans up after itself when its​
  32:        :     /// <see mref="Dispose" /> method is called, unless its​
  33:        :     /// <see pref="DoNotDelete" /> property is set to <b>true</b>.​
  34:        :     /// </summary>​
  35:        :     public class TestDirectory : IDisposable​
  36:        :     {​
  37:        :         #region Logging​
  38:        : 
  39:        :         private static Logger _log = LogManager.GetCurrentClassLogger();​
  40:        : 
  41:        :         #endregion​
  42:        : 
  43:        :         private readonly string _folder;​
  44:        : 
  45:        :         /// <summary>​
  46:        :         /// Initializes a new instance of the <see cref="TestDirectory" />​
  47:        :         /// class.​
  48:        :         /// </summary>​
  49:        :         public TestDirectory()​
  50:        :         {​
  51:     1/1:             _folder = Path.Combine(Path.GetTempPath(),​
  52:     1/1:                                    "NinjaTurtles",​
  53:     1/1:                                    Guid.NewGuid().ToString("N"));​
  54:     1/1:             _log.Debug("Creating folder \"{0}\".", _folder);​
  55:     1/1:             Directory.CreateDirectory(_folder);​
  56:        :         }​
  57:        : 
  58:        :         /// <summary>​
  59:        :         /// Initializes a new instance of the <see cref="TestDirectory" />​
  60:        :         /// class.​
  61:        :         /// </summary>​
  62:        :         /// <param name="sourceFolder">​
  63:        :         /// The name of a folder whose contents should be recursively​
  64:        :         /// copied to the temporary folder.​
  65:        :         /// </param>​
  66:        :         public TestDirectory(string sourceFolder)​
  67:        :             : this()​
  68:        :         {​
  69:     2/2:             _log.Debug("Copying contents from folder \"{0}\".", sourceFolder);​
  70:     3/3:             CopyDirectoryContents(sourceFolder, _folder);​
  71:        :         }​
  72:        : 
  73:        :         /// <summary>​
  74:        :         /// Saves an image of a mutated assembly into the root of the test​
  75:        :         /// directory.​
  76:        :         /// </summary>​
  77:        :         /// <param name="module"></param>​
  78:        :         public void SaveAssembly(Module module)​
  79:        :         {​
  80:     3/3:             string fileName = Path.GetFileName(module.AssemblyLocation);​
  81:     7/7:             string path = Path.Combine(_folder, fileName);​
  82:     5/5:             _log.Debug("Writing assembly \"{0}\" to \"{1}\".", fileName, _folder);​
  83:     3/3:             module.AssemblyDefinition.Write(path);​
  84:        :         }​
  85:        : 
  86:        :         private static void CopyDirectoryContents​
  87:        :             (string directory, string targetDirectory)​
  88:        :         {​
  89:   19/19:             foreach (var file in Directory.GetFiles(directory))​
  90:        :             {​
  91:   11/11:                 string fileName = Path.GetFileName(file);​
  92:     7/7:                 _log.Trace("Copying file \"{0}\".", fileName);​
  93:   17/17:                 string target = Path.Combine(targetDirectory, fileName);​
  94:   13/13:                 File.Copy(file, target);​
  95:     5/5:             }​
  96:   19/19:             foreach (var subDirectory in Directory.GetDirectories(directory))​
  97:        :             {​
  98:   11/11:                 string subDirectoryName = Path.GetFileName(subDirectory);​
  99:     7/7:                 _log.Trace("Creating subdirectory \"{0}\".", subDirectoryName);​
 100:   17/17:                 string target = Path.Combine(targetDirectory, subDirectoryName);​
 101:     7/7:                 Directory.CreateDirectory(target);​
 102:   13/13:                 CopyDirectoryContents(subDirectory, target);​
 103:     5/5:             }​
 104:        :         }​
 105:        : 
 106:        :         /// <summary>​
 107:        :         /// Gets the full path of the test directory.​
 108:        :         /// </summary>​
 109:        :         public string FullName​
 110:        :         {​
 111:        :             get { return _folder; }​
 112:        :         }​
 113:        : 
 114:        :         /// <summary>​
 115:        :         /// Performs application-defined tasks associated with freeing,​
 116:        :         /// releasing, or resetting unmanaged resources.​
 117:        :         /// </summary>​
 118:        :         public void Dispose()​
 119:        :         {​
 120:     5/5:             if (DoNotDelete)​
 121:        :             {​
 122:     1/1:                 return;​
 123:        :             }​
 124:        :             try​
 125:        :             {​
 126:     2/2:                 _log.Debug("Deleting folder \"{0}\".", _folder);​
 127:     2/2:                 Directory.Delete(_folder, true);​
 128:     1/1:             }​
 129:     1/1:             catch (Exception ex)​
 130:        :             {​
 131:     3/3:                 string message = string.Format("Failed to delete folder \"{0}\".", _folder);​
 132:     2/2:                 _log.ErrorException(message, ex);​
 133:     2/2:             }​
 134:        :         }​
 135:        : 
 136:        :         /// <summary>​
 137:        :         /// Gets or sets a flag indicating whether or not the contents of the​
 138:        :         /// test directory should be allowed to remain on disk when the​
 139:        :         /// instance is disposed.​
 140:        :         /// </summary>​
 141:        :         public bool DoNotDelete { get; set; }​
 142:        :     }​
 143:        : }​
 144:        : 

TypeResolver.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Linq;​
  25:        : using System.Reflection;​
  26:        : 
  27:        : using NLog;​
  28:        : 
  29:        : namespace NinjaTurtles​
  30:        : {​
  31:        :     internal class TypeResolver​
  32:        :     {​
  33:        :         #region Logging​
  34:        : 
  35:        :         private static Logger _log = LogManager.GetCurrentClassLogger();​
  36:        : 
  37:        :         #endregion​
  38:        : 
  39:        :         internal static Type ResolveTypeFromReferences(Assembly callingAssembly, string className)​
  40:        :         {​
  41:     1/1:             _log.Debug("Resolving type \"{0}\" in \"{1}\".", className, callingAssembly.GetName().Name);​
  42:     2/2:             Type type = ResolveTypeFromReferences(callingAssembly, className, new List<string>());​
  43:     6/6:             if (type == null)​
  44:        :             {​
  45:     1/1:                 _log.Error("Could not find type \"{0}\".", className);​
  46:        :             }​
  47:     2/2:             return type;​
  48:        :         }​
  49:        : 
  50:        :         private static Type ResolveTypeFromReferences(Assembly assembly, string className, IList<string> consideredAssemblies)​
  51:        :         {​
  52:     2/2:             _log.Trace("Searching for type \"{0}\" in \"{1}\".", className, assembly.GetName().Name);​
  53:     3/3:             var type = assembly.GetTypes().SingleOrDefault(t => t.FullName == className);​
  54:     6/6:             if (type != null)​
  55:        :             {​
  56:     2/2:                 _log.Trace("Found type \"{0}\" in \"{1}\".", className, assembly.GetName().Name);​
  57:     3/3:                 return type;​
  58:        :             }​
  59:   10/10:             foreach (var reference in assembly.GetReferencedAssemblies())​
  60:        :             {​
  61:     6/6:                 if (consideredAssemblies.Contains(reference.Name)) continue;​
  62:     1/1:                 consideredAssemblies.Add(reference.Name);​
  63:     1/1:                 Assembly referencedAssembly = Assembly.Load(reference);​
  64:     3/3:                 type = ResolveTypeFromReferences(referencedAssembly, className, consideredAssemblies);​
  65:     6/6:                 if (type != null)​
  66:        :                 {​
  67:     3/3:                     return type;​
  68:        :                 }​
  69:     5/5:             }​
  70:     3/3:             return null;​
  71:        :         }​
  72:        :     }​
  73:        : }​
  74:        : 

VariableReadTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Linq;​
  25:        : 
  26:        : using Mono.Cecil;​
  27:        : using Mono.Cecil.Cil;​
  28:        : 
  29:        : namespace NinjaTurtles.Turtles​
  30:        : {​
  31:        :     /// <summary>​
  32:        :     /// An implementation of <see cref="IMethodTurtle" /> that identifies local​
  33:        :     /// variables, method parameters and fields of the same type, and permutes​
  34:        :     /// any reads from them. For example, if two <see cref="Int32" />​
  35:        :     /// parameters <c>a</c> and <c>b</c> exist, along with a local variable​
  36:        :     /// <c>c</c> of the same type, then a read from <c>a</c> will be replaced​
  37:        :     /// by one from <c>b</c> and <c>c</c> in turn, and so on.​
  38:        :     /// </summary>​
  39:        :     public class VariableReadTurtle : MethodTurtleBase​
  40:        :     {​
  41:        :         /// <summary>​
  42:        :         /// Performs the actual code mutations, returning each with​
  43:        :         /// <c>yield</c> for the calling code to use.​
  44:        :         /// </summary>​
  45:        :         /// <remarks>​
  46:        :         /// Implementing classes should yield the result obtained by calling​
  47:        :         /// the <see mref="DoYield" /> method.​
  48:        :         /// </remarks>​
  49:        :         /// <param name="method">​
  50:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  51:        :         /// testing is to be carried out.​
  52:        :         /// </param>​
  53:        :         /// <param name="module">​
  54:        :         /// A <see cref="Module" /> representing the main module of the​
  55:        :         /// containing assembly.​
  56:        :         /// </param>​
  57:        :         /// <returns>​
  58:        :         /// An <see cref="IEnumerable{T}" /> of​
  59:        :         /// <see cref="MutantMetaData" /> structures.​
  60:        :         /// </returns>​
  61:        :         protected override IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module)​
  62:        :         {​
  63:     1/1:             var variablesByType = GroupVariablesByType(method);​
  64:     1/1:             PopulateOperandsInVariables(method, variablesByType);​
  65:        : 
  66:     7/7:             if (!variablesByType.Any(kv => variablesByType[kv.Key].Count > 1))​
  67:        :             {​
  68:     1/1:                 yield break;​
  69:        :             }​
  70:        : 
  71:   13/13:             foreach (var keyValuePair in variablesByType.Where(kv => kv.Value.Count > 1))​
  72:        :             {​
  73:     1/1:                 var variables = keyValuePair.Value.ToList();​
  74:   22/22:                 for (int index = 0; index < method.Body.Instructions.Count; index++)​
  75:        :                 {​
  76:     4/4:                     var instruction = method.Body.Instructions[index];​
  77:   11/11:                     if (instruction.OpCode == OpCodes.Ldloc && instruction.Next.OpCode == OpCodes.Ret) continue;​
  78:        : 
  79:     4/4:                     int oldIndex = -1;​
  80:     7/7:                     if (instruction.OpCode == OpCodes.Ldarg)​
  81:        :                     {​
  82:     1/1:                         int parameterIndex = ((ParameterDefinition)instruction.Operand).Sequence;​
  83:     4/4:                         oldIndex = variables.FindIndex(v => v.Type == VariableType.Parameter && v.Index == parameterIndex);​
  84:        :                     }​
  85:     7/7:                     if (instruction.OpCode == OpCodes.Ldloc)​
  86:        :                     {​
  87:     1/1:                         int variableIndex = ((VariableDefinition)instruction.Operand).Index;​
  88:     4/4:                         oldIndex = variables.FindIndex(v => v.Type == VariableType.Local && v.Index == variableIndex);​
  89:        :                     }​
  90:     7/7:                     if (instruction.OpCode == OpCodes.Ldfld)​
  91:        :                     {​
  92:     1/1:                         string fieldName = ((FieldDefinition)instruction.Operand).Name;​
  93:     4/4:                         oldIndex = variables.FindIndex(v => v.Type == VariableType.Field && v.Name == fieldName);​
  94:        :                     }​
  95:        : 
  96:   12/12:                     if (oldIndex < 0) continue;​
  97:        : 
  98:     1/1:                     OpCode originalOpCode = instruction.OpCode;​
  99:     1/1:                     object originalOperand = instruction.Operand;​
 100:     5/5:                     var originalVariable = variables[oldIndex];​
 101:        : 
 102:   22/22:                     for (int newIndex = 0; newIndex < variables.Count; newIndex++)​
 103:        :                     {​
 104:   14/14:                         if (newIndex == oldIndex) continue;​
 105:     5/5:                         var variable = variables[newIndex];​
 106:     9/9:                         if (variable.Operand == null) continue;​
 107:        : 
 108:   18/18:                         if (variable.Type == VariableType.Parameter​
 109:   18/18:                             && instruction.OpCode == OpCodes.Ldloc​
 110:   18/18:                             && instruction.Previous.OpCode == OpCodes.Stloc​
 111:   18/18:                             && ((VariableDefinition)instruction.Operand).Index == ((VariableDefinition)instruction.Previous.Operand).Index​
 112:   18/18:                             && instruction.Previous.Previous.OpCode == OpCodes.Ldarg​
 113:   18/18:                             && ((ParameterDefinition)instruction.Previous.Previous.Operand).Index == variable.Index)​
 114:        :                         {​
 115:        :                             // The .NET compiler sometimes adds a pointless​
 116:        :                             // cache of a parameter into a local variable​
 117:        :                             // (oddly, Mono doesn't seem to). We need to not​
 118:        :                             // mutate in this scenario.​
 119:     1/1:                             continue;​
 120:        :                         }​
 121:        : 
 122:     7/7:                         if (instruction.IsPartOfCompilerGeneratedDispose())​
 123:        :                         {​
 124:     1/1:                             continue;​
 125:        :                         }​
 126:        : 
 127:     2/2:                         instruction.OpCode = variable.GetReadOpCode();​
 128:     2/2:                         instruction.Operand = variable.Operand;​
 129:        : 
 130:     6/6:                         var description =​
 131:     6/6:                             string.Format(​
 132:     6/6:                                 "{0:x4}: read substitution {1}.{2} => {1}.{3}",​
 133:     6/6:                                 GetOriginalOffset(index),​
 134:     6/6:                                 keyValuePair.Key.Name,​
 135:     6/6:                                 originalVariable.Name,​
 136:     6/6:                                 variable.Name);​
 137:        : 
 138:     4/4:                         var mutantMetaData = DoYield(method, module, description, index);​
 139:     4/4:                         yield return mutantMetaData;​
 140:        :                     }​
 141:     1/1:                     instruction.OpCode = originalOpCode;​
 142:     1/1:                     instruction.Operand = originalOperand;​
 143:        :                 }​
 144:        :             }​
 145:        :         }​
 146:        : 
 147:        :         private static IDictionary<TypeReference, IList<Variable>> GroupVariablesByType(MethodDefinition method)​
 148:        :         {​
 149:        :             IDictionary<TypeReference, IList<Variable>> variables = new Dictionary<TypeReference, IList<Variable>>();​
 150:        :             int offset = method.IsStatic ? 0 : 1;​
 151:        :             foreach (var parameter in method.Parameters)​
 152:        :             {​
 153:        :                 var type = parameter.ParameterType;​
 154:        :                 if (!variables.ContainsKey(type))​
 155:        :                 {​
 156:        :                     variables.Add(type, new List<Variable>());​
 157:        :                 }​
 158:        :                 variables[type].Add(new Variable(VariableType.Parameter, parameter.Index + offset, parameter.Name));​
 159:        :             }​
 160:        :             foreach (var variable in method.Body.Variables)​
 161:        :             {​
 162:        :                 var type = variable.VariableType;​
 163:        :                 if (!variables.ContainsKey(type))​
 164:        :                 {​
 165:        :                     variables.Add(type, new List<Variable>());​
 166:        :                 }​
 167:        :                 variables[type].Add(new Variable(VariableType.Local, variable.Index, variable.Name));​
 168:        :             }​
 169:        :             foreach (var field in method.DeclaringType.Fields)​
 170:        :             {​
 171:        :                 if (field.Name == "<>1__state") continue;​
 172:        :                 var type = field.FieldType;​
 173:        :                 if (!variables.ContainsKey(type))​
 174:        :                 {​
 175:        :                     variables.Add(type, new List<Variable>());​
 176:        :                 }​
 177:        :                 variables[type].Add(new Variable(VariableType.Field, -1, field.Name));​
 178:        :             }​
 179:        :             return variables;​
 180:        :         }​
 181:        : 
 182:        :         private static void PopulateOperandsInVariables(MethodDefinition method, IDictionary<TypeReference, IList<Variable>> variables)​
 183:        :         {​
 184:        :             foreach (var instruction in method.Body.Instructions)​
 185:        :             {​
 186:        :                 if (instruction.OpCode == OpCodes.Ldarg)​
 187:        :                 {​
 188:        :                     var parameterDefinition = (ParameterDefinition)instruction.Operand;​
 189:        :                     int sequence = parameterDefinition.Sequence;​
 190:        :                     if (!variables.ContainsKey(parameterDefinition.ParameterType)) continue;​
 191:        :                     var variable =​
 192:        :                         variables[parameterDefinition.ParameterType]​
 193:        :                             .SingleOrDefault(v => v.Type == VariableType.Parameter && v.Index == sequence);​
 194:        :                     if (variable != null)​
 195:        :                     {​
 196:        :                         variable.Operand = instruction.Operand;​
 197:        :                     }​
 198:        :                 }​
 199:        :                 if (instruction.OpCode == OpCodes.Ldloc)​
 200:        :                 {​
 201:        :                     var variableDefinition = (VariableDefinition)instruction.Operand;​
 202:        :                     int index = variableDefinition.Index;​
 203:        :                     if (!variables.ContainsKey(variableDefinition.VariableType)) continue;​
 204:        :                     var variable =​
 205:        :                         variables[variableDefinition.VariableType]​
 206:        :                             .SingleOrDefault(v => v.Type == VariableType.Local && v.Index == index);​
 207:        :                     if (variable != null)​
 208:        :                     {​
 209:        :                         variable.Operand = instruction.Operand;​
 210:        :                     }​
 211:        :                 }​
 212:        :                 if (instruction.OpCode == OpCodes.Ldfld)​
 213:        :                 {​
 214:        :                     var fieldDefinition = (FieldDefinition)instruction.Operand;​
 215:        :                     string name = fieldDefinition.Name;​
 216:        :                     if (!variables.ContainsKey(fieldDefinition.FieldType)) continue;​
 217:        :                     var variable =​
 218:        :                         variables[fieldDefinition.FieldType]​
 219:        :                             .SingleOrDefault(v => v.Type == VariableType.Field && v.Name == name);​
 220:        :                     if (variable != null)​
 221:        :                     {​
 222:        :                         variable.Operand = instruction.Operand;​
 223:        :                     }​
 224:        :                 }​
 225:        :             }​
 226:        :         }​
 227:        :     }​
 228:        : }​

VariableWriteTurtle.cs

Line: Mutants: Source code                                                                       
   1:        : #region Copyright & licence​
   2:        : 
   3:        : // This file is part of NinjaTurtles.​
   4:        : // ​
   5:        : // NinjaTurtles is free software: you can redistribute it and/or modify​
   6:        : // it under the terms of the GNU Lesser General Public License as​
   7:        : // published by the Free Software Foundation, either version 3 of the​
   8:        : // License, or (at your option) any later version.​
   9:        : // ​
  10:        : // NinjaTurtles is distributed in the hope that it will be useful,​
  11:        : // but WITHOUT ANY WARRANTY; without even the implied warranty of​
  12:        : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the​
  13:        : // GNU Lesser General Public License for more details.​
  14:        : // ​
  15:        : // You should have received a copy of the GNU Lesser General Public​
  16:        : // License along with NinjaTurtles.  If not, see <http://www.gnu.org/licenses/>.​
  17:        : // ​
  18:        : // Copyright (C) 2012 David Musgrove and others.​
  19:        : 
  20:        : #endregion​
  21:        : 
  22:        : using System;​
  23:        : using System.Collections.Generic;​
  24:        : using System.Linq;​
  25:        : 
  26:        : using Mono.Cecil;​
  27:        : using Mono.Cecil.Cil;​
  28:        : 
  29:        : namespace NinjaTurtles.Turtles​
  30:        : {​
  31:        :     /// <summary>​
  32:        :     /// An implementation of <see cref="IMethodTurtle" /> that identifies local​
  33:        :     /// variables of the same type, and permutes any assignments to them. For​
  34:        :     /// example, if two <see cref="Int32" /> variables <c>a</c> and <c>b</c>​
  35:        :     /// exist, then an assignment to <c>a</c> will be replaced by one to​
  36:        :     /// <c>b</c>, and vice versa.​
  37:        :     /// </summary>​
  38:        :     public class VariableWriteTurtle : MethodTurtleBase​
  39:        :     {​
  40:        :         /// <summary>​
  41:        :         /// Performs the actual code mutations, returning each with​
  42:        :         /// <c>yield</c> for the calling code to use.​
  43:        :         /// </summary>​
  44:        :         /// <remarks>​
  45:        :         /// Implementing classes should yield the result obtained by calling​
  46:        :         /// the <see mref="DoYield" /> method.​
  47:        :         /// </remarks>​
  48:        :         /// <param name="method">​
  49:        :         /// A <see cref="MethodDefinition" /> for the method on which mutation​
  50:        :         /// testing is to be carried out.​
  51:        :         /// </param>​
  52:        :         /// <param name="module">​
  53:        :         /// A <see cref="Module" /> representing the main module of the​
  54:        :         /// containing assembly.​
  55:        :         /// </param>​
  56:        :         /// <returns>​
  57:        :         /// An <see cref="IEnumerable{T}" /> of​
  58:        :         /// <see cref="MutantMetaData" /> structures.​
  59:        :         /// </returns>​
  60:        :         protected override IEnumerable<MutantMetaData> DoMutate(MethodDefinition method, Module module)​
  61:        :         {​
  62:     1/1:             var variablesByType = GroupVariablesByType(method);​
  63:     1/1:             PopulateOperandsInVariables(method, variablesByType);​
  64:        : 
  65:   13/13:             foreach (var keyValuePair in variablesByType.Where(kv => kv.Value.Count > 1))​
  66:        :             {​
  67:     1/1:                 var variables = keyValuePair.Value.ToList();​
  68:   22/22:                 for (int index = 0; index < method.Body.Instructions.Count; index++)​
  69:        :                 {​
  70:     4/4:                     var instruction = method.Body.Instructions[index];​
  71:     8/8:                     if (instruction.IsPartOfCompilerGeneratedDispose()) continue;​
  72:        : 
  73:     4/4:                     int oldIndex = -1;​
  74:     7/7:                     if (instruction.OpCode == OpCodes.Stloc)​
  75:        :                     {​
  76:     1/1:                         int variableIndex = ((VariableDefinition)instruction.Operand).Index;​
  77:     4/4:                         oldIndex = variables.FindIndex(v => v.Type == VariableType.Local && v.Index == variableIndex);​
  78:        :                     }​
  79:     7/7:                     if (instruction.OpCode == OpCodes.Stfld)​
  80:        :                     {​
  81:     1/1:                         string fieldName = ((FieldDefinition)instruction.Operand).Name;​
  82:     4/4:                         oldIndex = variables.FindIndex(v => v.Type == VariableType.Field && v.Name == fieldName);​
  83:        :                     }​
  84:        : 
  85:   12/12:                     if (oldIndex < 0) continue;​
  86:        : 
  87:        :                     // Skip if could be initialising to zero, as in reality​
  88:        :                     // this has already been done by the CLR.​
  89:   10/10:                     if (instruction.Previous.OpCode == OpCodes.Ldc_I4​
  90:   10/10:                         && (int)instruction.Previous.Operand == 0)​
  91:        :                     {​
  92:     1/1:                         continue;​
  93:        :                     }​
  94:        : 
  95:     1/1:                     OpCode originalOpCode = instruction.OpCode;​
  96:     1/1:                     object originalOperand = instruction.Operand;​
  97:     5/5:                     var originalVariable = variables[oldIndex];​
  98:        : 
  99:   22/22:                     for (int newIndex = 0; newIndex < variables.Count; newIndex++)​
 100:        :                     {​
 101:   14/14:                         if (newIndex == oldIndex) continue;​
 102:     5/5:                         var variable = variables[newIndex];​
 103:     9/9:                         if (variable.Operand == null) continue;​
 104:        : 
 105:     2/2:                         instruction.OpCode = variable.GetWriteOpCode();​
 106:     2/2:                         instruction.Operand = variable.Operand;​
 107:        : 
 108:     6/6:                         var description =​
 109:     6/6:                             string.Format(​
 110:     6/6:                                 "{0:x4}: write substitution {1}.{2} => {1}.{3}",​
 111:     6/6:                                 GetOriginalOffset(index),​
 112:     6/6:                                 keyValuePair.Key.Name,​
 113:     6/6:                                 originalVariable.Name,​
 114:     6/6:                                 variable.Name);​
 115:        : 
 116:     6/6:                         yield return DoYield(method, module, description, index);​
 117:        : 
 118:        :                     }​
 119:     1/1:                     instruction.OpCode = originalOpCode;​
 120:     1/1:                     instruction.Operand = originalOperand;​
 121:        :                 }​
 122:        :             }​
 123:        :         }​
 124:        : 
 125:        :         private static IDictionary<TypeReference, IList<Variable>> GroupVariablesByType(MethodDefinition method)​
 126:        :         {​
 127:        :             IDictionary<TypeReference, IList<Variable>> variables = new Dictionary<TypeReference, IList<Variable>>();​
 128:        :             foreach (var variable in method.Body.Variables)​
 129:        :             {​
 130:        :                 var type = variable.VariableType;​
 131:        :                 if (!variables.ContainsKey(type))​
 132:        :                 {​
 133:        :                     variables.Add(type, new List<Variable>());​
 134:        :                 }​
 135:        :                 variables[type].Add(new Variable(VariableType.Local, variable.Index, variable.Name));​
 136:        :             }​
 137:        :             foreach (var field in method.DeclaringType.Fields)​
 138:        :             {​
 139:        :                 if (field.Name == "<>1__state") continue;​
 140:        :                 var type = field.FieldType;​
 141:        :                 if (!variables.ContainsKey(type))​
 142:        :                 {​
 143:        :                     variables.Add(type, new List<Variable>());​
 144:        :                 }​
 145:        :                 variables[type].Add(new Variable(VariableType.Field, -1, field.Name));​
 146:        :             }​
 147:        :             return variables;​
 148:        :         }​
 149:        : 
 150:        :         private static void PopulateOperandsInVariables(MethodDefinition method, IDictionary<TypeReference, IList<Variable>> variables)​
 151:        :         {​
 152:        :             foreach (var instruction in method.Body.Instructions)​
 153:        :             {​
 154:        :                 if (instruction.OpCode == OpCodes.Ldloc)​
 155:        :                 {​
 156:        :                     var variableDefinition = (VariableDefinition)instruction.Operand;​
 157:        :                     int index = variableDefinition.Index;​
 158:        :                     if (!variables.ContainsKey(variableDefinition.VariableType)) continue;​
 159:        :                     var variable =​
 160:        :                         variables[variableDefinition.VariableType]​
 161:        :                             .SingleOrDefault(v => v.Type == VariableType.Local && v.Index == index);​
 162:        :                     if (variable != null)​
 163:        :                     {​
 164:        :                         variable.Operand = instruction.Operand;​
 165:        :                     }​
 166:        :                 }​
 167:        :                 if (instruction.OpCode == OpCodes.Ldfld)​
 168:        :                 {​
 169:        :                     var fieldDefinition = (FieldDefinition)instruction.Operand;​
 170:        :                     string name = fieldDefinition.Name;​
 171:        :                     if (!variables.ContainsKey(fieldDefinition.FieldType)) continue;​
 172:        :                     var variable =​
 173:        :                         variables[fieldDefinition.FieldType]​
 174:        :                             .SingleOrDefault(v => v.Type == VariableType.Field && v.Name == name);​
 175:        :                     if (variable != null)​
 176:        :                     {​
 177:        :                         variable.Operand = instruction.Operand;​
 178:        :                     }​
 179:        :                 }​
 180:        :             }​
 181:        :         }​
 182:        :     }​
 183:        : }​