Coder Social home page Coder Social logo

stryker-mutator / stryker-net Goto Github PK

View Code? Open in Web Editor NEW
1.7K 26.0 175.0 9.64 MB

Mutation testing for .NET core and .NET framework!

Home Page: https://stryker-mutator.io

License: Apache License 2.0

C# 99.65% JavaScript 0.20% HTML 0.05% F# 0.10%
mutation-testing stryker dotnet-core dotnet-framework hacktoberfest dotnet-stryker

stryker-net's People

Contributors

0xced avatar bforslund avatar cmulder avatar dependabot-preview[bot] avatar dependabot[bot] avatar dukedagmor avatar dupdob avatar energy164 avatar hugo-vrijswijk avatar konh avatar liam-rougoor avatar mobrockers avatar pbonnema avatar psfinaki avatar renovate[bot] avatar richardelekta avatar richardwerkman avatar robertlyson avatar rouke-broersma avatar sbergen avatar simoncropp avatar simondel avatar stijn-rutten avatar tom171296 avatar tommysor avatar valdas3 avatar xandervedder avatar yaelkeemink avatar yakivyusin avatar ysbakker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stryker-net's Issues

Errorhandling

Right now there are 2 kinds of custom exceptions, both inherrit from StrykerException. I initially thought there would be much more kinds of exceptions, but it turned out this is not the case.

I would like to see one kind of custom exception, for example UserException or InputException. It should contain a message that clearly explains to the user what they did wrong and how they can invoke Stryker.NET right next time. Everything that the user can fix themselves should be shown to them using this kind of exception.

  • Initital testrun failed
  • Initial build failed
  • Arguments wrong
  • 2 project references found

I would like to see that the user sees no stacktrace in this case, only a clear message about what they did wrong and how they can improve. A stacktrace could give wrong impressions to users, as they think Stryker.NET is broken.

I suggest the following:

  • The Core project will handle all exceptions by logging them (except the custom exceptions)
  • The CLI project will handle the custom exceptions without a stacktrace

Return an exit code from Stryker CLI

It would be helpful if we could set a threshold for the Mutation score that if not reached would result in the process returning non-zero exit code.

Also failures (like the one described in #120) causes the process to exit with 0.

For CI purposes it is fundamental to return a proper exit code.

replace logFile with log-level-file

In stryker js there is no argument called logFile. the closest argument is logLevelFile. I would like to see that implementation instead of logFile

waffle.io board

Use the following lanes:

  • Inbox
  • Committed
  • In progress
  • Needs review
  • Done

Build and release using Azure DevOps Pipelines

Azure DevOps pipelines are now free for open source projects. We could use them to easily build, test and release our application(s). Integrating with SonarCloud would also be easier from Azure DevOps.

Changelog strategy

How will we create the changelog for new releases?

For Stryker itself, we use conventional commit messages. With those we can generate beautiful changelogs. It also helps to clean up our commit messages. A win-win situation.

An example would be: feat(parser): add ability to parse arrays.. This translates to:

""

Features

Parser: add ability to parse arrays.
""

For C# i would suggest taking a look at clog: https://github.com/clog-tool

@richardwerkman if you agree: i would suggest starting squashing PR into single commits while using these commit messages.

Ternary statement mutations

At the moment, mutations are being placed inside if statements like this

if(Environment.GetEnvironmentVariable("ActiveMutation") == "<id>") {
    // mutation
} else {
    // original
}

Not all mutations can be inserted like this. Some mutations can only be inserted using ternary statements like this:

var localVariable = if(Environment.GetEnvironmentVariable("ActiveMutation") == "<id>") ? // mutation : //original

These kind of mutations should also be rollbacked different. My suggestion is an interface for both type of mutant placements. Something like:

public interface IMutantPlacement {
    SyntaxNode InsertMutant(SyntaxNode, Mutant);
    SyntaxNode RemoveMutant(SyntaxNode, Mutant);
}

It would have two implementations. One for if statements and one for ternary mutations.

Mutated assembly conflicts with code coverage analysis

After a mutationtestrun the mutated assembly stays in place. It is located in the test project bin folder. When code coverage is analysed with the mutated assembly in place this influcences the code coverage result.

This is due to the added if statements inside the mutated assembly. They are not hit (of course) during the code coverage analysis.

This could be resolved by removing the mutated assembly after Stryker is done. Stryker could replace it with the original assembly file to leave all files as they were before the run.

Technical references

Where would we like to document our technical references? Things like:

  • How the mutation algorithm works
  • How Mutators can be added
  • How the different packages work together

I see some options but would like to share thoughts.

  1. GitHub wiki
  2. Markdown files in a sub-folder
  3. External website

Especially diagrams are hard to maintain together. Maybe some sequence/activity diagrams could be useful. I've seen some tools that can generate diagrams from markdown. Which are best?

Thresholds

Right now the mutation score color thresholds are fixed at 60 and 80.

It would be nice to let users pass their own preferred thresholds. Also an extra threshold could be added for returning a non zero exit code.

Param suggestion: --thresholds 60 80 90 for:

  • < 60 return exit code 1
  • > 60 mutation score is red
  • > 80 mutation score is yellow
  • > 90 mutation score is green

Read settings from csproj file

Currently stryker supports reading its settings from a json file. Which I fine I guess. But most other dotnet CLI tools and Visual Studio plugins read their settings from the csproj file.

Not sure what led up to the decision to go with a JSON file, just curious if you thought about putting the settings inside the csproj file.

Getting different results on different OSes

Stryker is reporting different results on different OSes.

TL;DR

While testing Stryker I stumbled upon an intriguing issue, Stryker was reporting some non-killed mutants which I didn't think twice about as it seemed it was working as expected. Then I uploaded the project to a private GitLab server and looked at CI results, one mutant was killed (which didn't happen on my Windows 10 PC).

The issue

When running on Windows 10 (log-20180928-windows-10.txt) or Ubuntu under Windows 10 (log-20180928-windows-10-linux.txt) all running .Net Core SDK 2.1.402 following mutant is marked as Survived but it shouldn't survive given the test case (see MutationTesting.zip).

Binary expression mutation on line 6: 'temp < 1000' ==> 'temp > 1000'

While running on Docker (image: microsoft/dotnet:2.1.402-sdk) it is killed as expected (log-20180928-linux-docker.txt).

I was trying to replicate on public GitLab server, but I got this error:

[13:49:31 ERR] An error occurred during the mutationtest run 
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: MaxDegreeOfParallelism
   at System.Threading.Tasks.ParallelOptions.set_MaxDegreeOfParallelism(Int32 value)
   at Stryker.Core.MutationTest.MutationTestProcess.Test()
   at Stryker.Core.StrykerRunner.RunMutationTest(StrykerOptions options)

During my testing I also got both mutants killed on Windows 10, which happened after I deleted my native language folder from SDK installation so I could send a proper (English speaking) report. Cleaning output folders did fix this issue and results got back to "normal".

AssignmentStatementMutator

Assignment statements can be mutated.

Original Mutated
+= -=
-= +=
*= /=
/= *=
%= *=
<<= >>=
>>= <<=
&= |=
|= &=

A mutator should be added that mutates these statements.

Progress reporter

Right now the only status reporter is the dot reporter. It will print dots and characters after a mutant has been tested.

It would be nice to show users a progress bar to show the progress of the mutationtestrun. A estimation could also be displayed next to the progress bar.

Multi threaded testruns

Right now only one testrun occurs at a time. This is not optimal since .Net is excellent in managing threads and parallel processes.

A better situation would be if more testrunners could run in parallel. The number of testrunners should be configurable. When not configured, the number of cores of the machine could be used as default.

This feature would speed up the mutationtest process by a large margin.

Support backslash in ProjectReference on Linux

When backslash (\) is used as folder separator in csproj (which is inserted by Visual Studio) when referencing another project in a solution, FileNotFoundException is thrown.

csproj snippet:

  <ItemGroup>
    <ProjectReference Include="..\..\src\Lib\Lib.csproj" />
  </ItemGroup>

Output:

Analyzing project
[12:21:49 INF] Using /builds/mutation-testing/tests/Lib.Tests/Lib.Tests.csproj as project file
[12:21:49 ERR] An error occurred during the mutationtest run 
System.IO.FileNotFoundException: Could not find file '/builds/mutation-testing/tests/Lib.Tests/..\..\src\Lib\Lib.csproj'.
File name: '/builds/mutation-testing/tests/Lib.Tests/..\..\src\Lib\Lib.csproj'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize)
   at System.IO.File.OpenText(String path)
   at Stryker.Core.Initialisation.InputFileResolver.FindProjectUnderTestAssemblyName(String projectFilePath)
   at Stryker.Core.Initialisation.InputFileResolver.ResolveInput(String currentDirectory, String projectName)
   at Stryker.Core.Initialisation.InitialisationProcess.Initialize(StrykerOptions options)
   at Stryker.Core.StrykerRunner.RunMutationTest(StrykerOptions options)
[12:21:49 INF] Time Elapsed 00:00:00.1874362

Workaround

Converting to slashes by hand fixes the issue.

Add validation for logLevel

At the moment you can give the CLI invalid loglevels which result in warning-loglevel. I think we might want to throw an error here.

Large projects

On large projects, it might occur that not all compile errors are returned by Roslyn after the first compile try. If this happens, not all "broken" mutations will be rollbacked.

For now this problem has not occurred yet. Stryker should be tested on a large project to discover if this is an existing bug or not.

Dashboard reporter

Stryker is currently working on a generic html dashboard for mutationtest results. To integrate with this dashboard we will have to generate a *.json file with the testrun results in a specific structure.

In this issue the json schema will be defined.

For now Stryker.NET can only generate the needed json. When the complete dashboard is done we can integrate it with the dashboard.

DotNetCore 2.1 support

On .NET Core 2.1 projects the build/dotnet-stryker.targets seems to be ignored. This file is being copied by msbuild in the other .NET Core versions.

An awesome feature is added in 2.1 called DotnetTools. This can be used to create global tools like with npm npm i -g

To support DotnetTool a new package has to be created with the type DotnetTool. This could also be added within the current CLI package.

For now the CLI seems to be broken on 2.1. To fix this users can copy the task by hand:

  <Target Name="PrintReferences" DependsOnTargets="ResolveProjectReferences;ResolveAssemblyReferences">
    <Message Text="@(_ResolveAssemblyReferenceResolvedFiles)" Importance="high" />
  </Target>

Into their test .csproj file

Merge interfaces and implementation

Right now it seems like every interface in in a separate file. I personally find it easier to find an interface and the implementation if the interface is in the same file as the implementation (as long as there is one implementation).

Exclude files from mutating

Right now, all *.cs files will be mutated by Stryker. Just like with code coverage, users would like to exclude some files.

I see two ways of excluding a file:

  • Using an array of filenames as userinput
  • By using Attributes inside the code

My preference goes to the attributes. Mainly because this option has more future posibilities like

  • excluding parts of files
  • excluding only sertain mutators using different attributes.

This could look like:

namespace Stryker.Core.Testing
{
    [ExcludeFromStryker]
    public class ProcessExecutor : IProcessExecutor
    {
namespace Stryker.Core.Testing
{
    [ExcludeFromStryker("BinaryMutator")]
    public class ProcessExecutor : IProcessExecutor
    {

Change RapportOnly to ReportOnly

In your solution you call the reports rapport. This is not english, it should be report. There is also at least one class with this mistake in it.

Checked mutator

int a = checked(b * c);

Should be mutated to:

int a = unchecked(b * c);

To see if a test is present for System.OverflowException was thrown. And maybe also the other way around. See dotnet csharplang for more info on the checked operator.

Mutation algorithm optimalisation

Right now all code is checked by every mutator. Some code is not fit for mutating so will always return 0 mutations. Therefore it is not necessary to check this code. Example:

using Stryker.Core.Initialisation.ProjectComponent;
using Stryker.Core.Mutants;
using Stryker.Core.Testing;
using System;
using System.Globalization;
using System.IO;
using System.Linq;

namespace Stryker.Core.Reporters
{
    /// <summary>
    /// The default reporter, prints a simple progress and end result.
    /// </summary>
    public class ConsoleRapportReporter : IReporter
    {

Cannot be mutated by any mutator. So why call the mutators onto these nodes?

Suggestion: only mutate method bodies.

Remove the need for a config file

Atm you must have a config file if you dont give any arguments to the CLI. I would like to be able to not give a config file and still dont have a config file.

It would be cool if we check whether there is a config file and if it does not exist we take the default values.

Read settings from a config file

We should be able to configure stryker via a config file. Right now, all config settings are provided using the command line.

This can be in the .csproj file or via a custom stryker configuration file.

It would be cool if this logic can be reused from stryker for dotnet core as well as .NET framework.

Parallel setting

The user should be able to define the number of parallel testruns. The default right now is the number of logical cores / 2.

dotnet stryker --parallel 2 
{
  "stryker-config": {
    "parallel": 2
  }
}

We should also explain clearly in the documentation what this setting does.

The number should be validated to be > 0 and be <= the number of logical cores.

<TargetFrameworks> causes Object null reference exception

When running against a test project using <TargetFrameworks> instead of <TargetFramework> causes a System.NullReferenceException.

[14:39:28 DBG] Determining project under test with name filter null
[14:39:28 ERR] An error occurred during the mutationtest run
System.NullReferenceException: Object reference not set to an instance of an object.
   at Stryker.Core.Initialisation.ProjectFileReader.FindTargetFrameworkReference(XDocument document)
   at Stryker.Core.Initialisation.ProjectFileReader.ReadProjectFile(XDocument projectFileContents, String projectUnderTestNameFilter)
   at Stryker.Core.Initialisation.InputFileResolver.ReadProjectFile(String projectFilePath, String projectName)
   at Stryker.Core.Initialisation.InputFileResolver.ResolveInput(String currentDirectory, String projectName)
   at Stryker.Core.Initialisation.InitialisationProcess.Initialize(StrykerOptions options)
   at Stryker.Core.StrykerRunner.RunMutationTest(StrykerOptions options)
[14:39:28 INF] Time Elapsed 00:00:00.2799214

The only indication that the issue is the TargetFramework is that the stack trace fails on FindTargetFrameworkReference. This could do with a better messaging if you only support targeting one framework, or better support when TargetFrameworks is used.

Configue extra files and folders to compile

Stryker has some problems with compiling a few projects as shown in #128.

If users could pass a list/array of files and folders to compile, Stryker would also be able to compile these projects.

{
    "stryker-config":
    {
        "files-to-compile": [
            "C:/some/location",
            "C:/another/location/specific-file.cs",
         ],
    }
}

We will have to test these values to be files of the right extension and scan the given folders for *.cs files. The content of the found files should be parsed to AST's and be fed to Roslyn before the first compilation.

@nicojs what do you think about this solution and the configuration name?

String mutator

A mutator should be added that mutates strings into other strings.

Original Mutated
"foo" (non-empty string) "" (empty string)
"" (empty string) "Stryker was here!"
$"foo {bar}" (string interpolation) $""

The mutator should look for StringLiteralExpression nodes

UnaryExpression mutator

Unary statements can be mutated.

PrefixUnaryStatements

Original Mutated
!variable variable
-variable +variable
+variable -variable
~variable variable
++variable --variable
--variable ++variable

PostfixUnaryStatements

Original Mutated
variable++ variable--
variable-- variable++

A mutator should be added that mutates these statements.

nuget contentfiles mutations causes issues

With nuget packages, you can include compilable source files: https://blog.nuget.org/20160126/nuget-contentFiles-demystified.html

These files end up compiled into the obj\Debug\netcoreapp2.1\NuGet\F3F32FCC102FAF927C28583AC554AF5CC6C67A63\MyLibrary\0.1.2 folder of the project that consumes them. They are effectively linked-in source files.

When Stryker mutates these files, it fails to mutate them back again (presumably because nuget automatically resets them?)

[12:26:48 ERR] Unable to rollback mutation for node EmptyQuery with diagnosticmessage The name 'EmptyQuery' does not exist in the current context
[12:26:48 ERR] An error occurred during the mutationtest run
System.ArgumentException: Node to track is not a descendant of the root.
   at Microsoft.CodeAnalysis.SyntaxNodeExtensions.TrackNodes[TRoot](TRoot root, IEnumerable`1 nodes) in /_/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions_Tracking.cs:line 43
   at Stryker.Core.Compiling.RollbackProcess.RemoveMutantIfStatements(SyntaxTree originalTree, ICollection`1 diagnosticInfo)
   at Stryker.Core.Compiling.RollbackProcess.Start(CSharpCompilation compiler, ImmutableArray`1 diagnostics)
   at Stryker.Core.Compiling.CompilingProcess.Compile(IEnumerable`1 syntaxTrees, MemoryStream ms)
   at Stryker.Core.MutationTest.MutationTestProcess.Mutate()
   at Stryker.Core.StrykerRunner.RunMutationTest(StrykerOptions options)

In the above message, EmptyQuery refers to a method defined in a base class inside the imported source contentFile from the nuget package.

It would be great if either compiled contentFiles from obj were ignored from mutation, and/or the ability to ignore files was added. The error looks similar to the error in #125

Align terminology of Mutator Types

In the handbook are the mutators described that are being used within the Stryker eco system. Now there is a mismatch of the terminology being used in documentation/code of Stryker.NET.

Binary mutator -> Binary Operators
Boolean mutator -> Boolean Substitutions
PrefixUnaryStatements -> Update operators or Boolean Substitutions
PostfixUnaryStatements -> Update operators

Contributions.md

I don't know how to contribute to this project because it lacks a contributions.md.
Plz fix, k thx.

Change argument names

Change the argument names to use dashes instead of camel case. For instance: timeoutMS will change to timeout-ms

Crash when code combines tuple deconstruction with ternary operator

On a small personal project to implement an immutable priority queue, Stryker.NET crashes with the following error:

[07:59:19 ERR] Unable to rollback mutation for node head with diagnosticmessage The name 'head' does not exist in the current context
[07:59:19 ERR] An error occurred during the mutationtest run
System.ArgumentException: Node to track is not a descendant of the root.
   at Microsoft.CodeAnalysis.SyntaxNodeExtensions.TrackNodes[TRoot](TRoot root, IEnumerable`1 nodes) in /_/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions_Tracking.cs:line 43
   at Stryker.Core.Compiling.RollbackProcess.RemoveMutantIfStatements(SyntaxTree originalTree, ICollection`1 diagnosticInfo)
   at Stryker.Core.Compiling.RollbackProcess.Start(CSharpCompilation compiler, ImmutableArray`1 diagnostics)
   at Stryker.Core.Compiling.CompilingProcess.Compile(IEnumerable`1 syntaxTrees, MemoryStream ms)
   at Stryker.Core.MutationTest.MutationTestProcess.Mutate()
   at Stryker.Core.StrykerRunner.RunMutationTest(StrykerOptions options)
[07:59:19 INF] Time Elapsed 00:00:10.8997693

Using the --logConsole trace flag I was able to isolate the cause to this piece of code:

var (head, toEnqueue) = _comparer(Head, value) <= 0
    ? (Head, value)
    : (value, Head);

BTW: thank you for including good diagnostic support!

As a workaround, I modified the code by removing use of tuples and the ternary operator:

T head;
T toEnqueue;
if (_comparer(Head, value) <= 0)
{
    head = Head;
    toEnqueue = value;
}
else
{
    head = value;
    toEnqueue = Head;
}

With this change, Stryker.NET doesn't crash on this piece of code ... though it does crash on two other very similar examples. Once those were similarly amended, all the mutants were tested - and bugs were identified. ๐Ÿ˜„

A simple ternary operator seems to be fine, and tuple deconstruction that doesn't require mutation also seems to be fine, so I suspect the problem occurs only with both language features combined.

Hanging process

When running stryker twice, the second time the initial build will fail becouse of a still running process. This still needs investigating but it looks like this happens after a timeout process kill.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.