diff --git a/AltCover.Engine/Cobertura.fs b/AltCover.Engine/Cobertura.fs index 5e959329..d9599d5b 100644 --- a/AltCover.Engine/Cobertura.fs +++ b/AltCover.Engine/Cobertura.fs @@ -1,6 +1,7 @@ namespace AltCover open System +open System.Collections.Generic open System.IO open System.Xml.Linq open System.Globalization @@ -76,12 +77,15 @@ module internal Cobertura = [] - let extractSource (values: (string * #(string seq)) seq) = + let extractSource (values: ((string * string seq) * string list) seq) = let starter = values |> Seq.head match Seq.length values with | 1 -> starter |> fst | _ -> // extract longest common prefix + let files = + values |> Seq.map fst |> Seq.collect snd + let l = values |> Seq.map (fun (_, split) -> Seq.length split) @@ -107,10 +111,11 @@ module internal Cobertura = |> Path.Combine let trimmed = prefix.Length - let source = fst starter + let source = starter |> fst |> fst - source.Substring(0, trimmed).Trim('\\') - + String([| Path.DirectorySeparatorChar |]) + (source.Substring(0, trimmed).Trim('\\') + + String([| Path.DirectorySeparatorChar |]), + files) [ Seq.map (fun s -> s.Attribute(attribute.X).Value) - |> Seq.filter (String.IsNullOrWhiteSpace >> not) - |> Seq.map Path.GetDirectoryName - |> Seq.filter (String.IsNullOrWhiteSpace >> not) - |> Seq.distinct - |> Seq.sort - let groupable = // (directory, facet list) - rawsources |> Seq.map (fun x -> (x, splitPath x)) + let table = + Dictionary() + + let rawsources = + files + |> Seq.filter (fun a -> + let fail = + a |> String.IsNullOrWhiteSpace |> not + + if fail then + table[Option.ofObj a] <- String.Empty + + fail) + |> Seq.map (fun a -> a, Path.GetDirectoryName a) + |> Seq.filter (fun (a, d) -> + let fail = + d |> String.IsNullOrWhiteSpace |> not + + if fail then + table[Option.ofObj a] <- a + + fail) + |> Seq.groupBy snd + |> Seq.map (fun (a, s) -> a, s |> Seq.map fst) + |> Seq.sortBy fst // seq of (directory, files full names) - let groups = // lead facet, (directory, facet list) seq + let groupable = // seq of ((directory, files full names), facets) + rawsources + |> Seq.map (fun x -> (x, x |> fst |> splitPath)) + + let groups = // seq of (root, seq of ((directory, files full names), facets)) groupable |> Seq.groupBy (snd >> grouping) let results = // throws away everything but the sources @@ -143,10 +170,19 @@ module internal Cobertura = results |> Seq.iter (fun f -> target.Descendants("sources".X) - |> Seq.iter _.Add(XElement("source".X, XText(f)))) + |> Seq.iter _.Add(XElement("source".X, XText(fst f)))) results // TODO - make look-up table - |> Seq.map (fun p -> p.Replace('\\', '/').Trim('/')) + |> Seq.iter (fun (p, files) -> + let prefix = + 1 + p.Replace('\\', '/').Trim('/').Length + + files + |> Seq.iter (fun f -> table[Some f] <- f.Substring(prefix)) + + ) + + table let internal nCover (report: XDocument) (packages: XElement) = @@ -239,13 +275,8 @@ module internal Cobertura = (hits, total) ((name, document: string), method) = - let normalized = document.Replace('\\', '/') - let filename = - sources - |> Seq.tryFind (fun s -> normalized.StartsWith(s, StringComparison.Ordinal)) - |> Option.map (fun start -> document.Substring(start.Length + 1)) - |> Option.defaultValue document + sources[Option.ofObj document] let ``class`` = XElement( @@ -511,13 +542,9 @@ module internal Cobertura = ((name, fileid), methodSet) = let document = files |> Map.find fileid - let normalized = document.Replace('\\', '/') let filename = - sources - |> Seq.tryFind (fun s -> normalized.StartsWith(s, StringComparison.Ordinal)) - |> Option.map (fun start -> document.Substring(start.Length + 1)) - |> Option.defaultValue document + sources[Option.ofObj document] let ``class`` = XElement( diff --git a/AltCover.Tests/Runner.Tests.fs b/AltCover.Tests/Runner.Tests.fs index 70541acd..6f468df1 100644 --- a/AltCover.Tests/Runner.Tests.fs +++ b/AltCover.Tests/Runner.Tests.fs @@ -6258,6 +6258,8 @@ module AltCoverRunnerTests = let sep = String([| Path.DirectorySeparatorChar |]) + let s = [ "some dummy value" ] |> List.toSeq + let cases = [ ([ "a" ], "a") ([ "a/b/"; "a/b/c" ], "a/b" + sep) @@ -6265,16 +6267,13 @@ module AltCoverRunnerTests = ([ "c:\\b\\x\\y"; "c:\\b\\c\\d" ], "c:\\b" + sep) ] |> List.map (fun (inputs, expect) -> (inputs - |> Seq.map (fun x -> (x, Cobertura.I.splitPath x))), + |> List.map (fun x -> ((x, s), Cobertura.I.splitPath x))), expect) Assert.Multiple(fun () -> cases |> Seq.iter (fun (case, expect) -> - test - <@ Cobertura.I.extractSource case = expect - - @>)) + test <@ case |> Cobertura.I.extractSource |> fst = expect @>)) [] let DegenerateCasesShouldNotGenerateCobertura () =