diff --git a/src/app/FakeLib/ReportGeneratorHelper.fs b/src/app/FakeLib/ReportGeneratorHelper.fs index 85d97c5f5be..22c8720263f 100644 --- a/src/app/FakeLib/ReportGeneratorHelper.fs +++ b/src/app/FakeLib/ReportGeneratorHelper.fs @@ -5,21 +5,22 @@ module Fake.ReportGeneratorHelper open System open System.Text -type ReportGeneratorReportType = +type ReportGeneratorReportType = | Html = 0 | HtmlSummary = 1 | Xml = 2 | XmlSummary = 3 | Latex = 4 | LatexSummary = 5 + | Badges = 6 -type ReportGeneratorLogVerbosity = +type ReportGeneratorLogVerbosity = | Verbose = 0 | Info = 1 | Error = 2 -/// ReportGenerator parameters, for more details see: https://reportgenerator.codeplex.com. -type ReportGeneratorParams = +/// ReportGenerator parameters, for more details see: https://github.com/danielpalme/ReportGenerator. +type ReportGeneratorParams = { /// (Required) Path to the ReportGenerator exe file. ExePath : string /// (Required) The directory where the generated report should be saved. @@ -29,7 +30,7 @@ type ReportGeneratorParams = /// Optional directories which contain the corresponding source code. SourceDirs : string list /// Optional list of assemblies that should be included or excluded - /// in the report. Exclusion filters take precedence over inclusion + /// in the report. Exclusion filters take precedence over inclusion /// filters. Wildcards are allowed. Filters : string list /// The verbosity level of the log messages. @@ -40,7 +41,7 @@ type ReportGeneratorParams = TimeOut : TimeSpan } /// ReportGenerator default parameters -let ReportGeneratorDefaultParams = +let ReportGeneratorDefaultParams = { ExePath = "./tools/ReportGenerator/bin/ReportGenerator.exe" TargetDir = currentDirectory ReportTypes = [ ReportGeneratorReportType.Html ] @@ -50,6 +51,22 @@ let ReportGeneratorDefaultParams = WorkingDir = currentDirectory TimeOut = TimeSpan.FromMinutes 5. } +/// Builds the report generator command line arguments from the given parameters and reports +/// [omit] +let buildReportGeneratorArgs parameters (reports : string seq) = + let reportTypes = parameters.ReportTypes |> List.map (fun rt -> rt.ToString()) + let sourceDirs = sprintf "-sourcedirs:%s" (String.Join(";", parameters.SourceDirs)) + let filters = sprintf "-filters:%s" (String.Join(";", parameters.Filters)) + + new StringBuilder() + |> append (sprintf "-reports:%s" (String.Join(";", reports))) + |> append (sprintf "-targetdir:%s" parameters.TargetDir) + |> appendWithoutQuotes (sprintf "-reporttypes:%s" (String.Join(";", reportTypes))) + |> appendIfTrue (parameters.SourceDirs.Length > 0) sourceDirs + |> appendIfTrue (parameters.Filters.Length > 0) filters + |> appendWithoutQuotes (sprintf "-verbosity:%s" (parameters.LogVerbosity.ToString())) + |> toText + /// Runs ReportGenerator on one or more coverage reports. /// ## Parameters /// @@ -59,35 +76,16 @@ let ReportGeneratorDefaultParams = /// ## Sample /// /// ReportGenerator (fun p -> { p with TargetDir = "c:/reports/" }) [ "c:/opencover.xml" ] -let ReportGenerator setParams (reports : string list) = +let ReportGenerator setParams (reports : string list) = let taskName = "ReportGenerator" let description = "Generating reports" traceStartTask taskName description let param = setParams ReportGeneratorDefaultParams - - let processArgs = - let args = ref (new StringBuilder()) - let append (s : string) = args := (!args).Append(s) - append "\"-reports:" - append (String.Join(";", reports)) - append "\" \"-targetdir:" - append param.TargetDir - append "\" -reporttypes:" - append (String.Join(";", param.ReportTypes |> List.map (fun rt -> rt.ToString()))) - if param.SourceDirs.Length > 0 then - append " \"-sourcedirs:" - append (String.Join(";", param.SourceDirs)) - append "\"" - if param.Filters.Length > 0 then - append " \"-filters:" - append (String.Join(";", param.Filters)) - append "\"" - append " -verbosity:" - append (param.LogVerbosity.ToString()) - (!args).ToString() + + let processArgs = buildReportGeneratorArgs param reports tracefn "ReportGenerator command\n%s %s" param.ExePath processArgs - let ok = - execProcess (fun info -> + let ok = + execProcess (fun info -> info.FileName <- param.ExePath if param.WorkingDir <> String.Empty then info.WorkingDirectory <- param.WorkingDir info.Arguments <- processArgs) param.TimeOut diff --git a/src/test/Test.FAKECore/ReportGeneratorHelperSpecs.cs b/src/test/Test.FAKECore/ReportGeneratorHelperSpecs.cs new file mode 100644 index 00000000000..c5b867730df --- /dev/null +++ b/src/test/Test.FAKECore/ReportGeneratorHelperSpecs.cs @@ -0,0 +1,107 @@ +using Fake; +using FSharp.Testing; +using Machine.Specifications; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Test.FAKECore +{ + [Subject(typeof(ReportGeneratorHelper), "report generator argument construction")] + internal abstract class BuildReportArgumentsSpecs + { + protected static ReportGeneratorHelper.ReportGeneratorParams Parameters; + protected static IEnumerable Reports; + protected static string Arguments; + + Establish context = () => + { + Parameters = ReportGeneratorHelper.ReportGeneratorDefaultParams; + Reports = Enumerable.Empty(); + }; + + Because of = () => + { + Arguments = ReportGeneratorHelper.buildReportGeneratorArgs(Parameters, Reports); + }; + + protected static readonly IEnumerable ReportTypes + = Enum.GetValues(typeof(ReportGeneratorHelper.ReportGeneratorReportType)) + .Cast(); + + protected static readonly IEnumerable ReportTypesAsText = ReportTypes.Select(rt => rt.ToString()); + } + + internal class when_executing_with_default_arguments : BuildReportArgumentsSpecs + { + It should_use_current_directory_as_target_directory = + () => Arguments.ShouldContain("-targetdir:" + Directory.GetCurrentDirectory()); + It should_only_use_html_report_type = + () => + { + Arguments.ShouldContain("-reporttypes:Html"); + foreach (string reportType in ReportTypesAsText.Except(new List { "Html" })) + { + Arguments.ShouldNotContain(reportType); + } + }; + It should_not_append_source_dirs = () => Arguments.ShouldNotContain("-sourcedirs:"); + It should_not_append_filters = () => Arguments.ShouldNotContain("-filters:"); + It should_have_a_log_verbosity_of_verbose = () => Arguments.ShouldContain("-verbosity:Verbose"); + } + + internal class when_appending_arguments : BuildReportArgumentsSpecs + { + It should_surround_reports_with_quotes = () => ArgumentsWithQuotes.ShouldContain("-reports:"); + It should_surround_target_directory_with_quotes = () => ArgumentsWithQuotes.ShouldContain("-targetdir:"); + It should_not_surround_report_types_with_quotes = () => ArgumentsWithQuotes.ShouldNotContain("-reporttypes:"); + It should_not_surround_verbosity_with_quotes = () => ArgumentsWithQuotes.ShouldNotContain("-verbosity:"); + + private static string ArgumentsWithQuotes = GetArgumentsWithQuotes(); + + private static string GetArgumentsWithQuotes() + { + var argumentsInQuotes = from Match match in Regex.Matches(Arguments, "\"([^\"]*)\"") + select match.ToString(); + + return string.Join("", argumentsInQuotes); + } + } + + internal class when_given_multiple_report_types : BuildReportArgumentsSpecs + { + Establish context = + () => Parameters = Parameters.With(p => p.ReportTypes, ReportTypes.ToFSharpList()); + + It should_delimit_report_types_with_semi_colon = + () => Arguments.ShouldContain("-reporttypes:" + string.Join(";", ReportTypesAsText)); + } + + internal class when_given_multiple_reports : BuildReportArgumentsSpecs + { + Establish context = + () => Reports = new List { "report.xml", "other-report.xml" }; + + It should_delimit_reports_with_semi_colon = + () => Arguments.ShouldContain("-reports:" + string.Join(";", Reports)); + } + + internal class when_given_one_or_more_source_directories : BuildReportArgumentsSpecs + { + Establish context = + () => Parameters = Parameters.With(p => p.SourceDirs, new List { "mydirectory" }.ToFSharpList()); + + It should_append_source_directories_with_quotes = + () => Arguments.ShouldContain("\"-sourcedirs:mydirectory\""); + } + + internal class when_given_one_or_more_filters : BuildReportArgumentsSpecs + { + Establish context = + () => Parameters = Parameters.With(p => p.Filters, new List { "+Included", "-Excluded" }.ToFSharpList()); + + It should_append_filters_with_quotes = () => Arguments.ShouldContain("\"-filters:+Included;-Excluded\""); + } +} diff --git a/src/test/Test.FAKECore/Test.FAKECore.csproj b/src/test/Test.FAKECore/Test.FAKECore.csproj index 1949789c6b2..271c751e0af 100644 --- a/src/test/Test.FAKECore/Test.FAKECore.csproj +++ b/src/test/Test.FAKECore/Test.FAKECore.csproj @@ -88,6 +88,7 @@ +