Skip to content

Commit a201004

Browse files
committed
fix quoting of module filter
1 parent 4e85b40 commit a201004

File tree

2 files changed

+99
-40
lines changed

2 files changed

+99
-40
lines changed

FineCodeCoverageTests/OpenCoverExeArgumentsProvider_Tests.cs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void Should_Safely_Include_The_TestDLLFile_In_The_TargetArgs()
6565

6666
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
6767

68-
AssertHasEscapedSetting(arguments, $"-targetargs:{OpenCoverExeEscaper.EscapeQuoteTargetArgsArgument("testDllFile")}");
68+
AssertHasEscapedSetting(arguments, $"-targetargs:{CommandLineArguments.EscapeQuotes("testDllFile")}");
6969
}
7070

7171
[Test]
@@ -78,7 +78,7 @@ public void Should_Safely_Include_The_Project_RunSettingsFile_In_The_TargetArgs_
7878

7979
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
8080

81-
AssertHasEscapedSetting(arguments, $"-targetargs:{OpenCoverExeEscaper.EscapeQuoteTargetArgsArgument("testDllFile")} /Settings:{OpenCoverExeEscaper.EscapeQuoteTargetArgsArgument("runSettingsFile")}");
81+
AssertHasEscapedSetting(arguments, $"-targetargs:{CommandLineArguments.EscapeQuotes("testDllFile")} /Settings:{CommandLineArguments.EscapeQuotes("runSettingsFile")}");
8282
}
8383

8484
[Test]
@@ -161,9 +161,55 @@ public void Should_Not_Add_ExcludeByFile_If_There_Are_None()
161161
var mockCoverageProject = SafeMockCoverageProject();
162162

163163
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
164+
164165
AssertDoesNotHaveSetting(arguments, "excludebyfile");
165166
}
166167

168+
[Test]
169+
public void Should_Safely_Filter_Include_Project_IncludedReferencedProjects_Space_Delimited()
170+
{
171+
var openCoverExeArgumentsProvider = new OpenCoverExeArgumentsProvider();
172+
var mockCoverageProject = SafeMockCoverageProject();
173+
mockCoverageProject.Setup(coverageProject => coverageProject.IncludedReferencedProjects)
174+
.Returns(new List<string> { "Referenced1", "Referenced2" });
175+
176+
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
177+
178+
AssertHasEscapedSetting(arguments, "-filter:+[Referenced1]* +[Referenced2]*");
179+
}
180+
181+
[Test]
182+
public void Should_Safely_Filter_Include_All_When_Exclude_And_No_Include()
183+
{
184+
Should_Safely_Filter_Exclude_Project_ExcludedReferencedProjects_Space_Delimited();
185+
}
186+
187+
[Test]
188+
public void Should_Safely_Filter_Exclude_Project_ExcludedReferencedProjects_Space_Delimited()
189+
{
190+
var openCoverExeArgumentsProvider = new OpenCoverExeArgumentsProvider();
191+
var mockCoverageProject = SafeMockCoverageProject();
192+
mockCoverageProject.Setup(coverageProject => coverageProject.ExcludedReferencedProjects)
193+
.Returns(new List<string> { "Referenced1", "Referenced2" });
194+
195+
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
196+
197+
AssertHasEscapedSetting(arguments, "-filter:+[*]* -[Referenced1]* -[Referenced2]*");
198+
}
199+
200+
[Test]
201+
public void Should_Safely_Filter_Exclude_Trimmed_Project_Excludes_Trimmed_Of_Spaces_And_Quotes_Space_Delimited()
202+
{
203+
var openCoverExeArgumentsProvider = new OpenCoverExeArgumentsProvider();
204+
var mockCoverageProject = SafeMockCoverageProject();
205+
mockCoverageProject.Setup(coverageProject => coverageProject.Settings.Exclude)
206+
.Returns(new string[] { " '[Exclude1]*' ", " \"[Exclude2]* \" " });
207+
208+
var arguments = openCoverExeArgumentsProvider.Provide(mockCoverageProject.Object, "");
209+
210+
AssertHasEscapedSetting(arguments, "-filter:+[*]* -[Exclude1]* -[Exclude2]*");
211+
}
212+
167213
private Mock<ICoverageProject> SafeMockCoverageProject()
168214
{
169215
var mockCoverageProject = new Mock<ICoverageProject>();
@@ -185,7 +231,7 @@ private void AssertHasSetting(List<string> openCoverSettings, string setting)
185231

186232
private void AssertHasEscapedSetting(List<string> openCoverSettings, string setting)
187233
{
188-
AssertHasSetting(openCoverSettings, OpenCoverExeEscaper.EscapeArgument(setting));
234+
AssertHasSetting(openCoverSettings, CommandLineArguments.EscapeArgument(setting));
189235
}
190236
}
191237
}

SharedProject/Core/OpenCover/OpenCoverExeArgumentsProvider.cs

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,78 +6,91 @@
66

77
namespace FineCodeCoverage.Engine.OpenCover
88
{
9-
internal static class OpenCoverExeEscaper
9+
internal static class CommandLineArguments
1010
{
1111
public static string EscapeArgument(string value)
1212
{
1313
return $@"""{value}""";
1414
}
1515

16-
public static string EscapeQuoteTargetArgsArgument(string arg)
16+
public static string EscapeQuotes(string arg)
1717
{
1818
return $@"\""{arg}\""";
1919
}
2020
}
2121
[Export(typeof(IOpenCoverExeArgumentsProvider))]
2222
internal class OpenCoverExeArgumentsProvider : IOpenCoverExeArgumentsProvider
2323
{
24+
private enum Delimiter { Semicolon, Space}
2425
private void AddFilter(ICoverageProject project, List<string> opencoverSettings)
2526
{
26-
var filters = new List<string>();
27-
var defaultFilter = "+[*]*";
28-
29-
foreach (var value in (project.Settings.Include ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
30-
{
31-
filters.Add($@"+{value.Replace("\"", "\\\"").Trim(' ', '\'')}");
32-
}
33-
34-
foreach (var includedReferencedProject in project.IncludedReferencedProjects)
27+
var includeFilters = GetExcludesOrIncludes(project.Settings.Include, project.IncludedReferencedProjects,true);
28+
var excludeFilters = GetExcludesOrIncludes(project.Settings.Exclude, project.ExcludedReferencedProjects,false);
29+
AddIncludeAllIfExcludingWithoutIncludes();
30+
var filters = includeFilters.Concat(excludeFilters).ToList();
31+
SafeAddToSettingsDelimitedIfAny(opencoverSettings, "filter", filters, Delimiter.Space);
32+
33+
void AddIncludeAllIfExcludingWithoutIncludes()
3534
{
36-
filters.Add($@"+[{includedReferencedProject}]*");
35+
if (excludeFilters.Any() && !includeFilters.Any())
36+
{
37+
includeFilters.Add("+[*]*");
38+
}
3739
}
3840

39-
if (!filters.Any())
41+
List<string> GetExcludesOrIncludes(string[] excludesOrIncludes,List<string> referencedExcludesOrIncludes, bool isInclude)
4042
{
41-
filters.Add(defaultFilter);
42-
}
43+
var excludeOrIncludeFilters = new List<string>();
44+
var prefix = IncludeSymbol(isInclude);
45+
excludesOrIncludes = SanitizeExcludesOrIncludes(excludesOrIncludes).ToArray();
46+
47+
foreach (var value in excludesOrIncludes)
48+
{
49+
excludeOrIncludeFilters.Add($@"{prefix}{value}");
50+
}
4351

44-
foreach (var value in (project.Settings.Exclude ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
45-
{
46-
filters.Add($@"-{value.Replace("\"", "\\\"").Trim(' ', '\'')}");
52+
foreach (var includedReferencedProject in referencedExcludesOrIncludes)
53+
{
54+
excludeOrIncludeFilters.Add(IncludeOrExclude(isInclude, includedReferencedProject));
55+
}
56+
return excludeOrIncludeFilters.Distinct().ToList();
4757
}
4858

49-
foreach (var referencedProjectExcludedFromCodeCoverage in project.ExcludedReferencedProjects)
59+
string IncludeOrExclude(bool include,string moduleFilter,string classFilter = "*")
5060
{
51-
filters.Add($@"-[{referencedProjectExcludedFromCodeCoverage}]*");
61+
var filter = IncludeSymbol(include);
62+
return $"{filter}[{moduleFilter}]{classFilter}";
5263
}
5364

54-
if (filters.Any(x => !x.Equals(defaultFilter)))
55-
{
56-
opencoverSettings.Add($@" ""-filter:{string.Join(" ", filters.Distinct())}"" ");
57-
}
58-
65+
string IncludeSymbol(bool include) => include ? "+" : "-";
5966
}
6067

61-
private IEnumerable<string> GetExcludes(string[] excludes)
68+
private IEnumerable<string> SanitizeExcludesOrIncludes(string[] excludesOrIncludes)
6269
{
63-
return (excludes ?? new string[0])
70+
return (excludesOrIncludes ?? new string[0])
6471
.Where(x => x != null)
6572
.Select(x => x.Trim(' ', '\'', '\"'))
6673
.Where(x => !string.IsNullOrWhiteSpace(x));
6774
}
6875

69-
private void SafeAddToSettingsSemiColonDelimitedIfAny(List<string> opencoverSettings,string settingName,IEnumerable<string> settings)
76+
private void SafeAddToSettingsDelimitedIfAny(
77+
List<string> opencoverSettings,
78+
string settingName,
79+
IEnumerable<string> settings,
80+
Delimiter delimiter = Delimiter.Semicolon
81+
)
7082
{
7183
if (settings.Any())
7284
{
73-
opencoverSettings.Add($@"""-{settingName}:{string.Join(";", settings)}""");
85+
var delimit = delimiter == Delimiter.Semicolon ? ";" : " ";
86+
opencoverSettings.Add($@"""-{settingName}:{string.Join(delimit, settings)}""");
7487
}
7588
}
7689

7790
private void AddExcludeByFile(ICoverageProject project, List<string> opencoverSettings)
7891
{
79-
var excludes = GetExcludes(project.Settings.ExcludeByFile).ToList();
80-
SafeAddToSettingsSemiColonDelimitedIfAny(opencoverSettings, "excludebyfile", excludes);
92+
var excludes = SanitizeExcludesOrIncludes(project.Settings.ExcludeByFile).ToList();
93+
SafeAddToSettingsDelimitedIfAny(opencoverSettings, "excludebyfile", excludes);
8194
}
8295

8396
private void AddExcludeByAttribute(ICoverageProject project, List<string> opencoverSettings)
@@ -89,14 +102,14 @@ private void AddExcludeByAttribute(ICoverageProject project, List<string> openco
89102
"ExcludeFromCodeCoverage"
90103
};
91104

92-
var excludes = GetExcludes(project.Settings.ExcludeByAttribute)
105+
var excludes = SanitizeExcludesOrIncludes(project.Settings.ExcludeByAttribute)
93106
.Concat(excludeFromCodeCoverageAttributes)
94107
.SelectMany(exclude => new[] { exclude, GetAlternateName(exclude) })
95108
.OrderBy(exclude => exclude)
96109
.Select(WildCardIfShortName);
97110

98111

99-
SafeAddToSettingsSemiColonDelimitedIfAny(opencoverSettings, "excludebyattribute", excludes);
112+
SafeAddToSettingsDelimitedIfAny(opencoverSettings, "excludebyattribute", excludes);
100113

101114
string WildCardIfShortName(string exclude)
102115
{
@@ -125,18 +138,18 @@ string GetAlternateName(string exclude)
125138

126139
private string GetTargetArgs(ICoverageProject project)
127140
{
128-
var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@" /Settings:{OpenCoverExeEscaper.EscapeQuoteTargetArgsArgument(project.RunSettingsFile)}" : default;
129-
return $@"""-targetargs:{OpenCoverExeEscaper.EscapeQuoteTargetArgsArgument(project.TestDllFile)}{runSettings}""";
141+
var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@" /Settings:{CommandLineArguments.EscapeQuotes(project.RunSettingsFile)}" : default;
142+
return $@"""-targetargs:{CommandLineArguments.EscapeQuotes(project.TestDllFile)}{runSettings}""";
130143
}
131144

132145
public List<string> Provide(ICoverageProject project,string msTestPlatformExePath)
133146
{
134147
var opencoverSettings = new List<string>();
135148

136-
opencoverSettings.Add(OpenCoverExeEscaper.EscapeArgument($"-target:{msTestPlatformExePath}"));
149+
opencoverSettings.Add(CommandLineArguments.EscapeArgument($"-target:{msTestPlatformExePath}"));
137150
opencoverSettings.Add(GetTargetArgs(project));
138151

139-
opencoverSettings.Add(OpenCoverExeEscaper.EscapeArgument($"-output:{project.CoverageOutputFile}"));
152+
opencoverSettings.Add(CommandLineArguments.EscapeArgument($"-output:{project.CoverageOutputFile}"));
140153

141154
AddFilter(project, opencoverSettings);
142155
AddExcludeByFile(project, opencoverSettings);

0 commit comments

Comments
 (0)