From b0c01bbe30678b3f14229bf980af29bc43c31e6b Mon Sep 17 00:00:00 2001 From: Petr Date: Sat, 23 Sep 2023 16:14:30 +0200 Subject: [PATCH 1/6] Simplifying DiffIgnoreChangesInput --- .../DiffProviders/GitDiffProviderTests.cs | 8 ++--- .../ExcludableStringTests.cs | 32 +++++++++++++++++++ .../{Options => }/FilePatternTests.cs | 2 +- .../Options/StrykerOptionsTests.cs | 2 +- .../Stryker.Core/ExcludableString.cs | 28 ++++++++++++++++ src/Stryker.Core/Stryker.Core/FilePattern.cs | 12 ++----- .../Options/Inputs/DiffIgnoreChangesInput.cs | 10 +++--- .../Stryker.Core/Options/StrykerOptions.cs | 2 +- 8 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs rename src/Stryker.Core/Stryker.Core.UnitTest/{Options => }/FilePatternTests.cs (98%) create mode 100644 src/Stryker.Core/Stryker.Core/ExcludableString.cs diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs index a82f3937ee..4f8467a221 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs @@ -213,7 +213,7 @@ public void ScanDiff_Throws_Stryker_Input_Exception_When_Commit_null() public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles() { // Arrange - var diffIgnoreFiles = new[] { new FilePattern(Glob.Parse("/c/Users/JohnDoe/Project/Tests/Test.cs"), false, null) }; + var diffIgnoreFiles = new[] { new ExcludableString("/c/Users/JohnDoe/Project/Tests/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -289,7 +289,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles() public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Single_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new FilePattern(Glob.Parse("/c/Users/JohnDoe/Project/*/Test.cs"), false, null) }; + var diffIgnoreFiles = new[] { new ExcludableString("/c/Users/JohnDoe/Project/*/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -365,7 +365,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Singl public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Multi_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new FilePattern(Glob.Parse("**/Test.cs"), false, null) }; + var diffIgnoreFiles = new[] { new ExcludableString("**/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -441,7 +441,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Multi public void ScanDiffReturnsListOfFiles_ExcludingFilesInDiffIgnoreFiles_Multi_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new FilePattern(Glob.Parse("**/file.cs"), false, null) }; + var diffIgnoreFiles = new[] { new ExcludableString("**/file.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs new file mode 100644 index 0000000000..ec716971c7 --- /dev/null +++ b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs @@ -0,0 +1,32 @@ +using System; +using Shouldly; +using Xunit; + +namespace Stryker.Core.UnitTest +{ + public class ExcludableStringTests : TestBase + { + [Fact] + public void ExcludableString_NullCtor() + { + Assert.Throws(() => new ExcludableString(null)); + } + + [Fact] + public void ExcludableString_NullParse() + { + Assert.Throws(() => ExcludableString.Parse(null)); + } + + [Fact] + public void ExcludableString_Globs() + { + var s1 = new ExcludableString(@"src/Person.cs"); + var s2 = new ExcludableString(@"!src\Person.cs"); + + s1.IsExcluded.ShouldBeFalse(); + s2.IsExcluded.ShouldBeTrue(); + s1.Glob.ToString().ShouldBe(s2.Glob.ToString()); + } + } +} diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/Options/FilePatternTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/FilePatternTests.cs similarity index 98% rename from src/Stryker.Core/Stryker.Core.UnitTest/Options/FilePatternTests.cs rename to src/Stryker.Core/Stryker.Core.UnitTest/FilePatternTests.cs index 432f764ef8..d8f8db2aeb 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/Options/FilePatternTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/FilePatternTests.cs @@ -5,7 +5,7 @@ using Shouldly; using Xunit; -namespace Stryker.Core.UnitTest.Options +namespace Stryker.Core.UnitTest { public class FilePatternTests : TestBase { diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs index 0e539a1fb5..32fddc95b8 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs @@ -26,7 +26,7 @@ public void ShouldCopyValues() DashboardUrl = "url", DevMode = true, Since = true, - DiffIgnoreChanges = new[] { new FilePattern(Glob.Parse("**"), true, null) }, + DiffIgnoreChanges = new[] { new ExcludableString("**") }, ExcludedMutations = new[] { Mutator.Bitwise }, FallbackVersion = "main", IgnoredMethods = new[] { new Regex("") }, diff --git a/src/Stryker.Core/Stryker.Core/ExcludableString.cs b/src/Stryker.Core/Stryker.Core/ExcludableString.cs new file mode 100644 index 0000000000..042250d906 --- /dev/null +++ b/src/Stryker.Core/Stryker.Core/ExcludableString.cs @@ -0,0 +1,28 @@ +using System; +using DotNet.Globbing; + +namespace Stryker.Core +{ + public class ExcludableString + { + public ExcludableString(string s) + { + if (s is null) + { + throw new ArgumentNullException(nameof(s)); + } + + IsExcluded = s.StartsWith('!'); + + var pattern = IsExcluded ? s[1..] : s; + var normalized = FilePathUtils.NormalizePathSeparators(pattern); + Glob = Glob.Parse(normalized); + } + + public bool IsExcluded { get; } + + public Glob Glob { get; } + + public static ExcludableString Parse(string s) => new(s); + } +} diff --git a/src/Stryker.Core/Stryker.Core/FilePattern.cs b/src/Stryker.Core/Stryker.Core/FilePattern.cs index 040bae02c4..7f3a2b05e4 100644 --- a/src/Stryker.Core/Stryker.Core/FilePattern.cs +++ b/src/Stryker.Core/Stryker.Core/FilePattern.cs @@ -39,14 +39,6 @@ public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection text /// public IReadOnlyCollection TextSpans { get; } - /// - /// Parses a given file pattern string. - /// Format: (!)<glob>({<spanStart>..<spanEnd>})* - /// - /// The pattern to parse. - /// The - public static FilePattern Parse(string pattern) => Parse(pattern, spansEnabled: true); - /// /// Parses a given file pattern string. /// Format: (!)<glob>({<spanStart>..<spanEnd>})* @@ -54,7 +46,7 @@ public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection text /// The pattern to parse. /// Enable or disable span parsing. /// The - public static FilePattern Parse(string pattern, bool spansEnabled) + public static FilePattern Parse(string pattern) { var exclude = false; IReadOnlyCollection textSpans; @@ -66,7 +58,7 @@ public static FilePattern Parse(string pattern, bool spansEnabled) } var textSpanGroupMatch = _textSpanGroupRegex.Match(pattern); - if (!spansEnabled || !textSpanGroupMatch.Success) + if (!textSpanGroupMatch.Success) { // If there are no spans specified, we add one that will cover the whole file. textSpans = new[] { _textSpanMaxValue }; diff --git a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs index 614e786a31..1771e8ee2b 100644 --- a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs +++ b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs @@ -14,19 +14,19 @@ Any non-excluded files will trigger all mutants to be tested because we cannot d Use glob syntax for wildcards: https://en.wikipedia.org/wiki/Glob_(programming) Example: ['**/*Assets.json','**/favicon.ico']"; - public IEnumerable Validate() + public IEnumerable Validate() { if (SuppliedInput is { }) { - var diffIgnoreFilePatterns = new List(); + var diffIgnoreStrings = new List(); foreach (var pattern in SuppliedInput) { - diffIgnoreFilePatterns.Add(FilePattern.Parse(FilePathUtils.NormalizePathSeparators(pattern), spansEnabled: false)); + diffIgnoreStrings.Add(ExcludableString.Parse(FilePathUtils.NormalizePathSeparators(pattern))); } - return diffIgnoreFilePatterns; + return diffIgnoreStrings; } - return Enumerable.Empty(); + return Enumerable.Empty(); } } } diff --git a/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs b/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs index 8d62d19a49..3c4fd26731 100644 --- a/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs +++ b/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs @@ -153,7 +153,7 @@ public class StrykerOptions /// Context: When using the since feature, all tests are run again if files in the test project change (as these could impact the test results) /// When the file is present in this option the tests should not run again as the file does not impact test results. /// - public IEnumerable DiffIgnoreChanges { get; init; } = Enumerable.Empty(); + public IEnumerable DiffIgnoreChanges { get; init; } = Enumerable.Empty(); /// /// When no previous report can be found for the since feature, this commitish is used to se a baseline. From e5cdaa056ede0b59da24919a807b1c440dd556e5 Mon Sep 17 00:00:00 2001 From: Petr Date: Sat, 23 Sep 2023 17:49:55 +0200 Subject: [PATCH 2/6] Update FilePattern.cs --- src/Stryker.Core/Stryker.Core/FilePattern.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Stryker.Core/Stryker.Core/FilePattern.cs b/src/Stryker.Core/Stryker.Core/FilePattern.cs index 7f3a2b05e4..509b77df8b 100644 --- a/src/Stryker.Core/Stryker.Core/FilePattern.cs +++ b/src/Stryker.Core/Stryker.Core/FilePattern.cs @@ -44,7 +44,6 @@ public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection text /// Format: (!)<glob>({<spanStart>..<spanEnd>})* /// /// The pattern to parse. - /// Enable or disable span parsing. /// The public static FilePattern Parse(string pattern) { From 4b95e317bb12caa467403cd67b6366e6082e7d35 Mon Sep 17 00:00:00 2001 From: Petr Date: Sat, 23 Sep 2023 18:24:10 +0200 Subject: [PATCH 3/6] Up --- .../ExcludableStringTests.cs | 20 +++++++++------- .../Stryker.Core/ExcludableString.cs | 23 +++++++++++++++---- src/Stryker.Core/Stryker.Core/FilePattern.cs | 20 ++++------------ .../Options/Inputs/DiffIgnoreChangesInput.cs | 2 +- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs index ec716971c7..186e324acb 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs @@ -7,15 +7,9 @@ namespace Stryker.Core.UnitTest public class ExcludableStringTests : TestBase { [Fact] - public void ExcludableString_NullCtor() + public void ExcludableString_Null() { - Assert.Throws(() => new ExcludableString(null)); - } - - [Fact] - public void ExcludableString_NullParse() - { - Assert.Throws(() => ExcludableString.Parse(null)); + _ = Assert.Throws(() => new ExcludableString(null)); } [Fact] @@ -28,5 +22,15 @@ public void ExcludableString_Globs() s2.IsExcluded.ShouldBeTrue(); s1.Glob.ToString().ShouldBe(s2.Glob.ToString()); } + + [Fact] + public void ExcludableString_MutantSpans() + { + var s1 = new ExcludableString(@"src/Person.cs{10..100}"); + var s2 = new ExcludableString(@"src/Person.cs"); + + s1.MutantSpans.ShouldBe("{10..100}"); + s2.MutantSpans.ShouldBeEmpty(); + } } } diff --git a/src/Stryker.Core/Stryker.Core/ExcludableString.cs b/src/Stryker.Core/Stryker.Core/ExcludableString.cs index 042250d906..3c95f92ef1 100644 --- a/src/Stryker.Core/Stryker.Core/ExcludableString.cs +++ b/src/Stryker.Core/Stryker.Core/ExcludableString.cs @@ -1,10 +1,13 @@ using System; +using System.Text.RegularExpressions; using DotNet.Globbing; namespace Stryker.Core { - public class ExcludableString + public readonly struct ExcludableString { + private static readonly Regex _mutantSpansRegex = new("(\\{(\\d+)\\.\\.(\\d+)\\})+$"); + public ExcludableString(string s) { if (s is null) @@ -15,14 +18,26 @@ public ExcludableString(string s) IsExcluded = s.StartsWith('!'); var pattern = IsExcluded ? s[1..] : s; - var normalized = FilePathUtils.NormalizePathSeparators(pattern); - Glob = Glob.Parse(normalized); + var mutantSpansRegex = _mutantSpansRegex.Match(pattern); + if (mutantSpansRegex.Success) + { + var filePathPart = pattern[..^mutantSpansRegex.Length]; + var normalized = FilePathUtils.NormalizePathSeparators(filePathPart); + Glob = Glob.Parse(normalized); + MutantSpans = mutantSpansRegex.Value; + } + else + { + var normalized = FilePathUtils.NormalizePathSeparators(pattern); + Glob = Glob.Parse(normalized); + MutantSpans = string.Empty; + } } public bool IsExcluded { get; } public Glob Glob { get; } - public static ExcludableString Parse(string s) => new(s); + public string MutantSpans { get; } } } diff --git a/src/Stryker.Core/Stryker.Core/FilePattern.cs b/src/Stryker.Core/Stryker.Core/FilePattern.cs index 509b77df8b..5cd468b376 100644 --- a/src/Stryker.Core/Stryker.Core/FilePattern.cs +++ b/src/Stryker.Core/Stryker.Core/FilePattern.cs @@ -13,7 +13,6 @@ namespace Stryker.Core /// public sealed class FilePattern : IEquatable { - private static readonly Regex _textSpanGroupRegex = new Regex("(\\{(\\d+)\\.\\.(\\d+)\\})+$"); private static readonly Regex _textSpanRegex = new Regex("\\{(\\d+)\\.\\.(\\d+)\\}"); private static readonly TextSpan _textSpanMaxValue = new TextSpan(0, int.MaxValue); @@ -47,17 +46,10 @@ public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection text /// The public static FilePattern Parse(string pattern) { - var exclude = false; + var s = new ExcludableString(pattern); IReadOnlyCollection textSpans; - if (pattern.StartsWith('!')) - { - exclude = true; - pattern = pattern[1..]; - } - - var textSpanGroupMatch = _textSpanGroupRegex.Match(pattern); - if (!textSpanGroupMatch.Success) + if (string.IsNullOrEmpty(s.MutantSpans)) { // If there are no spans specified, we add one that will cover the whole file. textSpans = new[] { _textSpanMaxValue }; @@ -65,18 +57,14 @@ public static FilePattern Parse(string pattern) else { // If we have one ore more spans we parse them. - var textSpansMatches = _textSpanRegex.Matches(textSpanGroupMatch.Value); + var textSpansMatches = _textSpanRegex.Matches(s.MutantSpans); textSpans = textSpansMatches .Select(x => TextSpan.FromBounds(int.Parse(x.Groups[1].Value), int.Parse(x.Groups[2].Value))) .Reduce() .ToList(); - - pattern = pattern.Substring(0, pattern.Length - textSpanGroupMatch.Length); } - var glob = Glob.Parse(FilePathUtils.NormalizePathSeparators(pattern)); - - return new FilePattern(glob, exclude, textSpans); + return new FilePattern(s.Glob, s.IsExcluded, textSpans); } /// diff --git a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs index 1771e8ee2b..253daac1ab 100644 --- a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs +++ b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs @@ -21,7 +21,7 @@ public IEnumerable Validate() var diffIgnoreStrings = new List(); foreach (var pattern in SuppliedInput) { - diffIgnoreStrings.Add(ExcludableString.Parse(FilePathUtils.NormalizePathSeparators(pattern))); + diffIgnoreStrings.Add(new ExcludableString(FilePathUtils.NormalizePathSeparators(pattern))); } return diffIgnoreStrings; From d9275a498e5ab1d07f55e604399316f45cf7c8e0 Mon Sep 17 00:00:00 2001 From: Petr Date: Sat, 23 Sep 2023 19:32:12 +0200 Subject: [PATCH 4/6] up --- .../Stryker.Core.UnitTest/ExcludableStringTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs index 186e324acb..ef535faea8 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs @@ -15,8 +15,8 @@ public void ExcludableString_Null() [Fact] public void ExcludableString_Globs() { - var s1 = new ExcludableString(@"src/Person.cs"); - var s2 = new ExcludableString(@"!src\Person.cs"); + var s1 = new ExcludableString(@"Person.cs"); + var s2 = new ExcludableString(@"!Person.cs"); s1.IsExcluded.ShouldBeFalse(); s2.IsExcluded.ShouldBeTrue(); From cd15c9e3b9e18500bea204ec9f9134aa2c44e5ef Mon Sep 17 00:00:00 2001 From: Petr Date: Sat, 30 Sep 2023 11:23:06 +0200 Subject: [PATCH 5/6] Rename the class --- .../DiffProviders/GitDiffProviderTests.cs | 8 ++++---- ...StringTests.cs => ExclusionPatternTests.cs} | 18 +++++++++--------- .../Options/StrykerOptionsTests.cs | 2 +- ...ExcludableString.cs => ExclusionPattern.cs} | 4 ++-- src/Stryker.Core/Stryker.Core/FilePattern.cs | 2 +- .../Options/Inputs/DiffIgnoreChangesInput.cs | 8 ++++---- .../Stryker.Core/Options/StrykerOptions.cs | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) rename src/Stryker.Core/Stryker.Core.UnitTest/{ExcludableStringTests.cs => ExclusionPatternTests.cs} (52%) rename src/Stryker.Core/Stryker.Core/{ExcludableString.cs => ExclusionPattern.cs} (93%) diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs index 4f8467a221..f18739c610 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/DiffProviders/GitDiffProviderTests.cs @@ -213,7 +213,7 @@ public void ScanDiff_Throws_Stryker_Input_Exception_When_Commit_null() public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles() { // Arrange - var diffIgnoreFiles = new[] { new ExcludableString("/c/Users/JohnDoe/Project/Tests/Test.cs") }; + var diffIgnoreFiles = new[] { new ExclusionPattern("/c/Users/JohnDoe/Project/Tests/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -289,7 +289,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles() public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Single_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new ExcludableString("/c/Users/JohnDoe/Project/*/Test.cs") }; + var diffIgnoreFiles = new[] { new ExclusionPattern("/c/Users/JohnDoe/Project/*/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -365,7 +365,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Singl public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Multi_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new ExcludableString("**/Test.cs") }; + var diffIgnoreFiles = new[] { new ExclusionPattern("**/Test.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() @@ -441,7 +441,7 @@ public void ScanDiffReturnsListOfFiles_ExcludingTestFilesInDiffIgnoreFiles_Multi public void ScanDiffReturnsListOfFiles_ExcludingFilesInDiffIgnoreFiles_Multi_Asterisk() { // Arrange - var diffIgnoreFiles = new[] { new ExcludableString("**/file.cs") }; + var diffIgnoreFiles = new[] { new ExclusionPattern("**/file.cs") }; var basePath = FilePathUtils.NormalizePathSeparators("/c/Users/JohnDoe/Project/Tests"); var options = new StrykerOptions() diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs similarity index 52% rename from src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs rename to src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs index ef535faea8..0fce206461 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/ExcludableStringTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs @@ -4,19 +4,19 @@ namespace Stryker.Core.UnitTest { - public class ExcludableStringTests : TestBase + public class ExclusionPatternTests : TestBase { [Fact] - public void ExcludableString_Null() + public void ExclusionPattern_Null() { - _ = Assert.Throws(() => new ExcludableString(null)); + _ = Assert.Throws(() => new ExclusionPattern(null)); } [Fact] - public void ExcludableString_Globs() + public void ExclusionPattern_Globs() { - var s1 = new ExcludableString(@"Person.cs"); - var s2 = new ExcludableString(@"!Person.cs"); + var s1 = new ExclusionPattern(@"Person.cs"); + var s2 = new ExclusionPattern(@"!Person.cs"); s1.IsExcluded.ShouldBeFalse(); s2.IsExcluded.ShouldBeTrue(); @@ -24,10 +24,10 @@ public void ExcludableString_Globs() } [Fact] - public void ExcludableString_MutantSpans() + public void ExclusionPattern_MutantSpans() { - var s1 = new ExcludableString(@"src/Person.cs{10..100}"); - var s2 = new ExcludableString(@"src/Person.cs"); + var s1 = new ExclusionPattern(@"src/Person.cs{10..100}"); + var s2 = new ExclusionPattern(@"src/Person.cs"); s1.MutantSpans.ShouldBe("{10..100}"); s2.MutantSpans.ShouldBeEmpty(); diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs index 32fddc95b8..6e7d1eab64 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/Options/StrykerOptionsTests.cs @@ -26,7 +26,7 @@ public void ShouldCopyValues() DashboardUrl = "url", DevMode = true, Since = true, - DiffIgnoreChanges = new[] { new ExcludableString("**") }, + DiffIgnoreChanges = new[] { new ExclusionPattern("**") }, ExcludedMutations = new[] { Mutator.Bitwise }, FallbackVersion = "main", IgnoredMethods = new[] { new Regex("") }, diff --git a/src/Stryker.Core/Stryker.Core/ExcludableString.cs b/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs similarity index 93% rename from src/Stryker.Core/Stryker.Core/ExcludableString.cs rename to src/Stryker.Core/Stryker.Core/ExclusionPattern.cs index 3c95f92ef1..a5ec3f0eb1 100644 --- a/src/Stryker.Core/Stryker.Core/ExcludableString.cs +++ b/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs @@ -4,11 +4,11 @@ namespace Stryker.Core { - public readonly struct ExcludableString + public readonly struct ExclusionPattern { private static readonly Regex _mutantSpansRegex = new("(\\{(\\d+)\\.\\.(\\d+)\\})+$"); - public ExcludableString(string s) + public ExclusionPattern(string s) { if (s is null) { diff --git a/src/Stryker.Core/Stryker.Core/FilePattern.cs b/src/Stryker.Core/Stryker.Core/FilePattern.cs index 5cd468b376..cc9491b5eb 100644 --- a/src/Stryker.Core/Stryker.Core/FilePattern.cs +++ b/src/Stryker.Core/Stryker.Core/FilePattern.cs @@ -46,7 +46,7 @@ public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection text /// The public static FilePattern Parse(string pattern) { - var s = new ExcludableString(pattern); + var s = new ExclusionPattern(pattern); IReadOnlyCollection textSpans; if (string.IsNullOrEmpty(s.MutantSpans)) diff --git a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs index 253daac1ab..805ac68822 100644 --- a/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs +++ b/src/Stryker.Core/Stryker.Core/Options/Inputs/DiffIgnoreChangesInput.cs @@ -14,19 +14,19 @@ Any non-excluded files will trigger all mutants to be tested because we cannot d Use glob syntax for wildcards: https://en.wikipedia.org/wiki/Glob_(programming) Example: ['**/*Assets.json','**/favicon.ico']"; - public IEnumerable Validate() + public IEnumerable Validate() { if (SuppliedInput is { }) { - var diffIgnoreStrings = new List(); + var diffIgnoreStrings = new List(); foreach (var pattern in SuppliedInput) { - diffIgnoreStrings.Add(new ExcludableString(FilePathUtils.NormalizePathSeparators(pattern))); + diffIgnoreStrings.Add(new ExclusionPattern(FilePathUtils.NormalizePathSeparators(pattern))); } return diffIgnoreStrings; } - return Enumerable.Empty(); + return Enumerable.Empty(); } } } diff --git a/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs b/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs index 3c4fd26731..78e4b43512 100644 --- a/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs +++ b/src/Stryker.Core/Stryker.Core/Options/StrykerOptions.cs @@ -153,7 +153,7 @@ public class StrykerOptions /// Context: When using the since feature, all tests are run again if files in the test project change (as these could impact the test results) /// When the file is present in this option the tests should not run again as the file does not impact test results. /// - public IEnumerable DiffIgnoreChanges { get; init; } = Enumerable.Empty(); + public IEnumerable DiffIgnoreChanges { get; init; } = Enumerable.Empty(); /// /// When no previous report can be found for the since feature, this commitish is used to se a baseline. From f65d8505940203805d1eda3193847429ec4024f3 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 2 Oct 2023 15:01:24 +0200 Subject: [PATCH 6/6] up --- .../ExclusionPatternTests.cs | 2 +- .../Stryker.Core/ExclusionPattern.cs | 16 +++++++++++----- src/Stryker.Core/Stryker.Core/FilePattern.cs | 10 +++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs b/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs index 0fce206461..faed616953 100644 --- a/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs +++ b/src/Stryker.Core/Stryker.Core.UnitTest/ExclusionPatternTests.cs @@ -29,7 +29,7 @@ public void ExclusionPattern_MutantSpans() var s1 = new ExclusionPattern(@"src/Person.cs{10..100}"); var s2 = new ExclusionPattern(@"src/Person.cs"); - s1.MutantSpans.ShouldBe("{10..100}"); + s1.MutantSpans.ShouldBe(new [] { (10, 100)}); s2.MutantSpans.ShouldBeEmpty(); } } diff --git a/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs b/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs index a5ec3f0eb1..1dd75a2dfc 100644 --- a/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs +++ b/src/Stryker.Core/Stryker.Core/ExclusionPattern.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; using DotNet.Globbing; @@ -6,7 +8,8 @@ namespace Stryker.Core { public readonly struct ExclusionPattern { - private static readonly Regex _mutantSpansRegex = new("(\\{(\\d+)\\.\\.(\\d+)\\})+$"); + private static readonly Regex _mutantSpanGroupRegex = new("(\\{(\\d+)\\.\\.(\\d+)\\})+$"); + private static readonly Regex _mutantSpanRegex = new Regex("\\{(\\d+)\\.\\.(\\d+)\\}"); public ExclusionPattern(string s) { @@ -18,19 +21,22 @@ public ExclusionPattern(string s) IsExcluded = s.StartsWith('!'); var pattern = IsExcluded ? s[1..] : s; - var mutantSpansRegex = _mutantSpansRegex.Match(pattern); + var mutantSpansRegex = _mutantSpanGroupRegex.Match(pattern); if (mutantSpansRegex.Success) { var filePathPart = pattern[..^mutantSpansRegex.Length]; var normalized = FilePathUtils.NormalizePathSeparators(filePathPart); Glob = Glob.Parse(normalized); - MutantSpans = mutantSpansRegex.Value; + + MutantSpans = _mutantSpanRegex + .Matches(mutantSpansRegex.Value) + .Select(x => (int.Parse(x.Groups[1].Value), int.Parse(x.Groups[2].Value))); } else { var normalized = FilePathUtils.NormalizePathSeparators(pattern); Glob = Glob.Parse(normalized); - MutantSpans = string.Empty; + MutantSpans = Enumerable.Empty<(int, int)>(); } } @@ -38,6 +44,6 @@ public ExclusionPattern(string s) public Glob Glob { get; } - public string MutantSpans { get; } + public IEnumerable<(int Start, int End)> MutantSpans { get; } } } diff --git a/src/Stryker.Core/Stryker.Core/FilePattern.cs b/src/Stryker.Core/Stryker.Core/FilePattern.cs index cc9491b5eb..44f7fb1dd2 100644 --- a/src/Stryker.Core/Stryker.Core/FilePattern.cs +++ b/src/Stryker.Core/Stryker.Core/FilePattern.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; namespace Stryker.Core { @@ -13,7 +12,6 @@ namespace Stryker.Core /// public sealed class FilePattern : IEquatable { - private static readonly Regex _textSpanRegex = new Regex("\\{(\\d+)\\.\\.(\\d+)\\}"); private static readonly TextSpan _textSpanMaxValue = new TextSpan(0, int.MaxValue); public FilePattern(Glob glob, bool isExclude, IReadOnlyCollection textSpans) @@ -49,17 +47,15 @@ public static FilePattern Parse(string pattern) var s = new ExclusionPattern(pattern); IReadOnlyCollection textSpans; - if (string.IsNullOrEmpty(s.MutantSpans)) + if (!s.MutantSpans.Any()) { // If there are no spans specified, we add one that will cover the whole file. textSpans = new[] { _textSpanMaxValue }; } else { - // If we have one ore more spans we parse them. - var textSpansMatches = _textSpanRegex.Matches(s.MutantSpans); - textSpans = textSpansMatches - .Select(x => TextSpan.FromBounds(int.Parse(x.Groups[1].Value), int.Parse(x.Groups[2].Value))) + textSpans = s.MutantSpans + .Select(x => TextSpan.FromBounds(x.Start, x.End)) .Reduce() .ToList(); }