11namespace AltCover
22
33open System
4+ open System.Collections .Generic
45open System.IO
56open System.Xml .Linq
67open System.Globalization
@@ -76,12 +77,15 @@ module internal Cobertura =
7677 [<SuppressMessage( " Gendarme.Rules.Performance" ,
7778 " AvoidRepetitiveCallsToPropertiesRule" ,
7879 Justification = " Compiler inlines" ) >]
79- let extractSource ( values : ( string * # ( string seq )) seq ) =
80+ let extractSource ( values : (( string * string seq ) * string list ) seq ) =
8081 let starter = values |> Seq.head
8182
8283 match Seq.length values with
8384 | 1 -> starter |> fst
8485 | _ -> // extract longest common prefix
86+ let files =
87+ values |> Seq.map fst |> Seq.collect snd
88+
8589 let l =
8690 values
8791 |> Seq.map ( fun ( _ , split ) -> Seq.length split)
@@ -107,10 +111,11 @@ module internal Cobertura =
107111 |> Path.Combine
108112
109113 let trimmed = prefix.Length
110- let source = fst starter
114+ let source = starter |> fst |> fst
111115
112- source.Substring( 0 , trimmed) .Trim( '\\' )
113- + String([| Path.DirectorySeparatorChar |])
116+ ( source.Substring( 0 , trimmed) .Trim( '\\' )
117+ + String([| Path.DirectorySeparatorChar |]),
118+ files)
114119
115120 [<System.Diagnostics.CodeAnalysis.SuppressMessage( " Gendarme.Rules.Maintainability" ,
116121 " AvoidUnnecessarySpecializationRule" ,
@@ -122,31 +127,62 @@ module internal Cobertura =
122127 ( tag : string )
123128 ( attribute : string )
124129 =
125- let rawsources =
130+ let files =
126131 report.Descendants( tag.X)
127132 |> Seq.map ( fun s -> s.Attribute( attribute.X) .Value)
128- |> Seq.filter ( fun a -> a |> String.IsNullOrWhiteSpace |> not )
129- |> Seq.map Path.GetDirectoryName
130- |> Seq.filter ( String.IsNullOrWhiteSpace >> not )
131- |> Seq.distinct
132- |> Seq.sort
133133
134- let groupable =
135- rawsources |> Seq.map ( fun x -> ( x, splitPath x))
134+ let table =
135+ Dictionary< string option, string>()
136+
137+ let rawsources =
138+ files
139+ |> Seq.filter ( fun a ->
140+ let fail =
141+ a |> String.IsNullOrWhiteSpace |> not
142+
143+ if fail then
144+ table[ Option.ofObj a] <- String.Empty
145+
146+ fail)
147+ |> Seq.map ( fun a -> a, Path.GetDirectoryName a)
148+ |> Seq.filter ( fun ( a , d ) ->
149+ let fail =
150+ d |> String.IsNullOrWhiteSpace |> not
151+
152+ if fail then
153+ table[ Option.ofObj a] <- a
154+
155+ fail)
156+ |> Seq.groupBy snd
157+ |> Seq.map ( fun ( a , s ) -> a, s |> Seq.map fst)
158+ |> Seq.sortBy fst // seq of (directory, files full names)
136159
137- let groups =
160+ let groupable = // seq of ((directory, files full names), facets)
161+ rawsources
162+ |> Seq.map ( fun x -> ( x, x |> fst |> splitPath))
163+
164+ let groups = // seq of (root, seq of ((directory, files full names), facets))
138165 groupable |> Seq.groupBy ( snd >> grouping)
139166
140- let results =
167+ let results = // throws away everything but the sources
141168 groups |> Seq.map ( snd >> extractSource)
142169
143170 results
144171 |> Seq.iter ( fun f ->
145172 target.Descendants( " sources" .X)
146- |> Seq.iter _. Add( XElement( " source" .X, XText( f))))
173+ |> Seq.iter _. Add( XElement( " source" .X, XText( fst f))))
147174
148- results
149- |> Seq.map ( fun p -> p.Replace( '\\' , '/' ) .Trim( '/' ))
175+ results // TODO - make look-up table
176+ |> Seq.iter ( fun ( p , files ) ->
177+ let prefix =
178+ 1 + p.Replace( '\\' , '/' ) .Trim( '/' ) .Length
179+
180+ files
181+ |> Seq.iter ( fun f -> table[ Some f] <- f.Substring( prefix))
182+
183+ )
184+
185+ table
150186
151187 let internal nCover ( report : XDocument ) ( packages : XElement ) =
152188
@@ -239,13 +275,8 @@ module internal Cobertura =
239275 ( hits , total )
240276 (( name , document : string ), method )
241277 =
242- let normalized = document.Replace( '\\' , '/' )
243-
244278 let filename =
245- sources
246- |> Seq.tryFind ( fun s -> normalized.StartsWith( s, StringComparison.Ordinal))
247- |> Option.map ( fun start -> document.Substring( start.Length + 1 ))
248- |> Option.defaultValue document
279+ sources[ Option.ofObj document]
249280
250281 let ``class`` =
251282 XElement(
@@ -511,13 +542,9 @@ module internal Cobertura =
511542 (( name , fileid ), methodSet )
512543 =
513544 let document = files |> Map.find fileid
514- let normalized = document.Replace( '\\' , '/' )
515545
516546 let filename =
517- sources
518- |> Seq.tryFind ( fun s -> normalized.StartsWith( s, StringComparison.Ordinal))
519- |> Option.map ( fun start -> document.Substring( start.Length + 1 ))
520- |> Option.defaultValue document
547+ sources[ Option.ofObj document]
521548
522549 let ``class`` =
523550 XElement(
0 commit comments