1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2020 The SwiftShader Authors. All Rights Reserved. 2*03ce13f7SAndroid Build Coastguard Worker// 3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*03ce13f7SAndroid Build Coastguard Worker// 7*03ce13f7SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*03ce13f7SAndroid Build Coastguard Worker// 9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License. 14*03ce13f7SAndroid Build Coastguard Worker 15*03ce13f7SAndroid Build Coastguard Workerpackage cov 16*03ce13f7SAndroid Build Coastguard Worker 17*03ce13f7SAndroid Build Coastguard Workerimport ( 18*03ce13f7SAndroid Build Coastguard Worker "fmt" 19*03ce13f7SAndroid Build Coastguard Worker "sort" 20*03ce13f7SAndroid Build Coastguard Worker "strings" 21*03ce13f7SAndroid Build Coastguard Worker) 22*03ce13f7SAndroid Build Coastguard Worker 23*03ce13f7SAndroid Build Coastguard Workertype treeFile struct { 24*03ce13f7SAndroid Build Coastguard Worker tcm TestCoverageMap 25*03ce13f7SAndroid Build Coastguard Worker spangroups map[SpanGroupID]SpanGroup 26*03ce13f7SAndroid Build Coastguard Worker allSpans SpanList 27*03ce13f7SAndroid Build Coastguard Worker} 28*03ce13f7SAndroid Build Coastguard Worker 29*03ce13f7SAndroid Build Coastguard Workerfunc newTreeFile() *treeFile { 30*03ce13f7SAndroid Build Coastguard Worker return &treeFile{ 31*03ce13f7SAndroid Build Coastguard Worker tcm: TestCoverageMap{}, 32*03ce13f7SAndroid Build Coastguard Worker spangroups: map[SpanGroupID]SpanGroup{}, 33*03ce13f7SAndroid Build Coastguard Worker } 34*03ce13f7SAndroid Build Coastguard Worker} 35*03ce13f7SAndroid Build Coastguard Worker 36*03ce13f7SAndroid Build Coastguard Worker// Tree represents source code coverage across a tree of different processes. 37*03ce13f7SAndroid Build Coastguard Worker// Each tree node is addressed by a Path. 38*03ce13f7SAndroid Build Coastguard Workertype Tree struct { 39*03ce13f7SAndroid Build Coastguard Worker initialized bool 40*03ce13f7SAndroid Build Coastguard Worker strings Strings 41*03ce13f7SAndroid Build Coastguard Worker spans map[Span]SpanID 42*03ce13f7SAndroid Build Coastguard Worker testRoot Test 43*03ce13f7SAndroid Build Coastguard Worker files map[string]*treeFile 44*03ce13f7SAndroid Build Coastguard Worker} 45*03ce13f7SAndroid Build Coastguard Worker 46*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) init() { 47*03ce13f7SAndroid Build Coastguard Worker if !t.initialized { 48*03ce13f7SAndroid Build Coastguard Worker t.strings.m = map[string]StringID{} 49*03ce13f7SAndroid Build Coastguard Worker t.spans = map[Span]SpanID{} 50*03ce13f7SAndroid Build Coastguard Worker t.testRoot = newTest() 51*03ce13f7SAndroid Build Coastguard Worker t.files = map[string]*treeFile{} 52*03ce13f7SAndroid Build Coastguard Worker t.initialized = true 53*03ce13f7SAndroid Build Coastguard Worker } 54*03ce13f7SAndroid Build Coastguard Worker} 55*03ce13f7SAndroid Build Coastguard Worker 56*03ce13f7SAndroid Build Coastguard Worker// Spans returns all the spans used by the tree 57*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) Spans() SpanList { 58*03ce13f7SAndroid Build Coastguard Worker out := make(SpanList, len(t.spans)) 59*03ce13f7SAndroid Build Coastguard Worker for span, id := range t.spans { 60*03ce13f7SAndroid Build Coastguard Worker out[id] = span 61*03ce13f7SAndroid Build Coastguard Worker } 62*03ce13f7SAndroid Build Coastguard Worker return out 63*03ce13f7SAndroid Build Coastguard Worker} 64*03ce13f7SAndroid Build Coastguard Worker 65*03ce13f7SAndroid Build Coastguard Worker// FileSpanGroups returns all the span groups for the given file 66*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) FileSpanGroups(path string) map[SpanGroupID]SpanGroup { 67*03ce13f7SAndroid Build Coastguard Worker return t.files[path].spangroups 68*03ce13f7SAndroid Build Coastguard Worker} 69*03ce13f7SAndroid Build Coastguard Worker 70*03ce13f7SAndroid Build Coastguard Worker// FileCoverage returns the TestCoverageMap for the given file 71*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) FileCoverage(path string) TestCoverageMap { 72*03ce13f7SAndroid Build Coastguard Worker return t.files[path].tcm 73*03ce13f7SAndroid Build Coastguard Worker} 74*03ce13f7SAndroid Build Coastguard Worker 75*03ce13f7SAndroid Build Coastguard Worker// Tests returns the root test 76*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) Tests() *Test { return &t.testRoot } 77*03ce13f7SAndroid Build Coastguard Worker 78*03ce13f7SAndroid Build Coastguard Worker// Strings returns the string table 79*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) Strings() Strings { return t.strings } 80*03ce13f7SAndroid Build Coastguard Worker 81*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) index(path Path) []indexedTest { 82*03ce13f7SAndroid Build Coastguard Worker out := make([]indexedTest, len(path)) 83*03ce13f7SAndroid Build Coastguard Worker test := &t.testRoot 84*03ce13f7SAndroid Build Coastguard Worker for i, p := range path { 85*03ce13f7SAndroid Build Coastguard Worker name := t.strings.index(p) 86*03ce13f7SAndroid Build Coastguard Worker test, out[i] = test.index(name) 87*03ce13f7SAndroid Build Coastguard Worker } 88*03ce13f7SAndroid Build Coastguard Worker return out 89*03ce13f7SAndroid Build Coastguard Worker} 90*03ce13f7SAndroid Build Coastguard Worker 91*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) addSpans(spans SpanList) SpanSet { 92*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(spans)) 93*03ce13f7SAndroid Build Coastguard Worker for _, s := range spans { 94*03ce13f7SAndroid Build Coastguard Worker id, ok := t.spans[s] 95*03ce13f7SAndroid Build Coastguard Worker if !ok { 96*03ce13f7SAndroid Build Coastguard Worker id = SpanID(len(t.spans)) 97*03ce13f7SAndroid Build Coastguard Worker t.spans[s] = id 98*03ce13f7SAndroid Build Coastguard Worker } 99*03ce13f7SAndroid Build Coastguard Worker out[id] = struct{}{} 100*03ce13f7SAndroid Build Coastguard Worker } 101*03ce13f7SAndroid Build Coastguard Worker return out 102*03ce13f7SAndroid Build Coastguard Worker} 103*03ce13f7SAndroid Build Coastguard Worker 104*03ce13f7SAndroid Build Coastguard Worker// Add adds the coverage information cov to the tree node addressed by path. 105*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) Add(path Path, cov *Coverage) { 106*03ce13f7SAndroid Build Coastguard Worker t.init() 107*03ce13f7SAndroid Build Coastguard Worker 108*03ce13f7SAndroid Build Coastguard Worker tests := t.index(path) 109*03ce13f7SAndroid Build Coastguard Worker 110*03ce13f7SAndroid Build Coastguard WorkernextFile: 111*03ce13f7SAndroid Build Coastguard Worker // For each file with coverage... 112*03ce13f7SAndroid Build Coastguard Worker for _, file := range cov.Files { 113*03ce13f7SAndroid Build Coastguard Worker // Lookup or create the file's test coverage map 114*03ce13f7SAndroid Build Coastguard Worker tf, ok := t.files[file.Path] 115*03ce13f7SAndroid Build Coastguard Worker if !ok { 116*03ce13f7SAndroid Build Coastguard Worker tf = newTreeFile() 117*03ce13f7SAndroid Build Coastguard Worker t.files[file.Path] = tf 118*03ce13f7SAndroid Build Coastguard Worker } 119*03ce13f7SAndroid Build Coastguard Worker 120*03ce13f7SAndroid Build Coastguard Worker for _, span := range file.Covered { 121*03ce13f7SAndroid Build Coastguard Worker tf.allSpans.Add(span) 122*03ce13f7SAndroid Build Coastguard Worker } 123*03ce13f7SAndroid Build Coastguard Worker for _, span := range file.Uncovered { 124*03ce13f7SAndroid Build Coastguard Worker tf.allSpans.Add(span) 125*03ce13f7SAndroid Build Coastguard Worker } 126*03ce13f7SAndroid Build Coastguard Worker 127*03ce13f7SAndroid Build Coastguard Worker // Add all the spans to the map, get the span ids 128*03ce13f7SAndroid Build Coastguard Worker spans := t.addSpans(file.Covered) 129*03ce13f7SAndroid Build Coastguard Worker 130*03ce13f7SAndroid Build Coastguard Worker // Starting from the test root, walk down the test tree. 131*03ce13f7SAndroid Build Coastguard Worker tcm, test := tf.tcm, t.testRoot 132*03ce13f7SAndroid Build Coastguard Worker parent := (*TestCoverage)(nil) 133*03ce13f7SAndroid Build Coastguard Worker for _, indexedTest := range tests { 134*03ce13f7SAndroid Build Coastguard Worker if indexedTest.created { 135*03ce13f7SAndroid Build Coastguard Worker if parent != nil && len(test.children) == 1 { 136*03ce13f7SAndroid Build Coastguard Worker parent.Spans = parent.Spans.addAll(spans) 137*03ce13f7SAndroid Build Coastguard Worker delete(parent.Children, indexedTest.index) 138*03ce13f7SAndroid Build Coastguard Worker } else { 139*03ce13f7SAndroid Build Coastguard Worker tc := tcm.index(indexedTest.index) 140*03ce13f7SAndroid Build Coastguard Worker tc.Spans = spans 141*03ce13f7SAndroid Build Coastguard Worker } 142*03ce13f7SAndroid Build Coastguard Worker continue nextFile 143*03ce13f7SAndroid Build Coastguard Worker } 144*03ce13f7SAndroid Build Coastguard Worker 145*03ce13f7SAndroid Build Coastguard Worker test = test.children[indexedTest.index] 146*03ce13f7SAndroid Build Coastguard Worker tc := tcm.index(indexedTest.index) 147*03ce13f7SAndroid Build Coastguard Worker 148*03ce13f7SAndroid Build Coastguard Worker // If the tree node contains spans that are not in this new test, 149*03ce13f7SAndroid Build Coastguard Worker // we need to push those spans down to all the other children. 150*03ce13f7SAndroid Build Coastguard Worker if lower := tc.Spans.removeAll(spans); len(lower) > 0 { 151*03ce13f7SAndroid Build Coastguard Worker // push into each child node 152*03ce13f7SAndroid Build Coastguard Worker for i := range test.children { 153*03ce13f7SAndroid Build Coastguard Worker child := tc.Children.index(TestIndex(i)) 154*03ce13f7SAndroid Build Coastguard Worker child.Spans = child.Spans.addAll(lower) 155*03ce13f7SAndroid Build Coastguard Worker } 156*03ce13f7SAndroid Build Coastguard Worker // remove from node 157*03ce13f7SAndroid Build Coastguard Worker tc.Spans = tc.Spans.removeAll(lower) 158*03ce13f7SAndroid Build Coastguard Worker } 159*03ce13f7SAndroid Build Coastguard Worker 160*03ce13f7SAndroid Build Coastguard Worker // The spans that are in the new test, but are not part of the tree 161*03ce13f7SAndroid Build Coastguard Worker // node carry propagating down. 162*03ce13f7SAndroid Build Coastguard Worker spans = spans.removeAll(tc.Spans) 163*03ce13f7SAndroid Build Coastguard Worker if len(spans) == 0 { 164*03ce13f7SAndroid Build Coastguard Worker continue nextFile 165*03ce13f7SAndroid Build Coastguard Worker } 166*03ce13f7SAndroid Build Coastguard Worker 167*03ce13f7SAndroid Build Coastguard Worker tcm = tc.Children 168*03ce13f7SAndroid Build Coastguard Worker parent = tc 169*03ce13f7SAndroid Build Coastguard Worker } 170*03ce13f7SAndroid Build Coastguard Worker } 171*03ce13f7SAndroid Build Coastguard Worker} 172*03ce13f7SAndroid Build Coastguard Worker 173*03ce13f7SAndroid Build Coastguard Worker// allSpans returns all the spans in use by the TestCoverageMap and its children. 174*03ce13f7SAndroid Build Coastguard Workerfunc (t *Tree) allSpans(tf *treeFile, tcm TestCoverageMap) SpanSet { 175*03ce13f7SAndroid Build Coastguard Worker spans := SpanSet{} 176*03ce13f7SAndroid Build Coastguard Worker for _, tc := range tcm { 177*03ce13f7SAndroid Build Coastguard Worker for id := tc.Group; id != nil; id = tf.spangroups[*id].Extend { 178*03ce13f7SAndroid Build Coastguard Worker group := tf.spangroups[*id] 179*03ce13f7SAndroid Build Coastguard Worker spans = spans.addAll(group.Spans) 180*03ce13f7SAndroid Build Coastguard Worker } 181*03ce13f7SAndroid Build Coastguard Worker spans = spans.addAll(tc.Spans) 182*03ce13f7SAndroid Build Coastguard Worker 183*03ce13f7SAndroid Build Coastguard Worker spans = spans.addAll(spans.invertAll(t.allSpans(tf, tc.Children))) 184*03ce13f7SAndroid Build Coastguard Worker } 185*03ce13f7SAndroid Build Coastguard Worker return spans 186*03ce13f7SAndroid Build Coastguard Worker} 187*03ce13f7SAndroid Build Coastguard Worker 188*03ce13f7SAndroid Build Coastguard Worker// StringID is an identifier of a string 189*03ce13f7SAndroid Build Coastguard Workertype StringID int 190*03ce13f7SAndroid Build Coastguard Worker 191*03ce13f7SAndroid Build Coastguard Worker// Strings holds a map of string to identifier 192*03ce13f7SAndroid Build Coastguard Workertype Strings struct { 193*03ce13f7SAndroid Build Coastguard Worker m map[string]StringID 194*03ce13f7SAndroid Build Coastguard Worker s []string 195*03ce13f7SAndroid Build Coastguard Worker} 196*03ce13f7SAndroid Build Coastguard Worker 197*03ce13f7SAndroid Build Coastguard Workerfunc (s *Strings) index(str string) StringID { 198*03ce13f7SAndroid Build Coastguard Worker i, ok := s.m[str] 199*03ce13f7SAndroid Build Coastguard Worker if !ok { 200*03ce13f7SAndroid Build Coastguard Worker i = StringID(len(s.s)) 201*03ce13f7SAndroid Build Coastguard Worker s.s = append(s.s, str) 202*03ce13f7SAndroid Build Coastguard Worker s.m[str] = i 203*03ce13f7SAndroid Build Coastguard Worker } 204*03ce13f7SAndroid Build Coastguard Worker return i 205*03ce13f7SAndroid Build Coastguard Worker} 206*03ce13f7SAndroid Build Coastguard Worker 207*03ce13f7SAndroid Build Coastguard Worker// TestIndex is an child test index 208*03ce13f7SAndroid Build Coastguard Workertype TestIndex int 209*03ce13f7SAndroid Build Coastguard Worker 210*03ce13f7SAndroid Build Coastguard Worker// Test is an collection of named sub-tests 211*03ce13f7SAndroid Build Coastguard Workertype Test struct { 212*03ce13f7SAndroid Build Coastguard Worker indices map[StringID]TestIndex 213*03ce13f7SAndroid Build Coastguard Worker children []Test 214*03ce13f7SAndroid Build Coastguard Worker} 215*03ce13f7SAndroid Build Coastguard Worker 216*03ce13f7SAndroid Build Coastguard Workerfunc newTest() Test { 217*03ce13f7SAndroid Build Coastguard Worker return Test{ 218*03ce13f7SAndroid Build Coastguard Worker indices: map[StringID]TestIndex{}, 219*03ce13f7SAndroid Build Coastguard Worker } 220*03ce13f7SAndroid Build Coastguard Worker} 221*03ce13f7SAndroid Build Coastguard Worker 222*03ce13f7SAndroid Build Coastguard Workertype indexedTest struct { 223*03ce13f7SAndroid Build Coastguard Worker index TestIndex 224*03ce13f7SAndroid Build Coastguard Worker created bool 225*03ce13f7SAndroid Build Coastguard Worker} 226*03ce13f7SAndroid Build Coastguard Worker 227*03ce13f7SAndroid Build Coastguard Workerfunc (t *Test) index(name StringID) (*Test, indexedTest) { 228*03ce13f7SAndroid Build Coastguard Worker idx, ok := t.indices[name] 229*03ce13f7SAndroid Build Coastguard Worker if !ok { 230*03ce13f7SAndroid Build Coastguard Worker idx = TestIndex(len(t.children)) 231*03ce13f7SAndroid Build Coastguard Worker t.children = append(t.children, newTest()) 232*03ce13f7SAndroid Build Coastguard Worker t.indices[name] = idx 233*03ce13f7SAndroid Build Coastguard Worker } 234*03ce13f7SAndroid Build Coastguard Worker return &t.children[idx], indexedTest{idx, !ok} 235*03ce13f7SAndroid Build Coastguard Worker} 236*03ce13f7SAndroid Build Coastguard Worker 237*03ce13f7SAndroid Build Coastguard Workertype namedIndex struct { 238*03ce13f7SAndroid Build Coastguard Worker name string 239*03ce13f7SAndroid Build Coastguard Worker idx TestIndex 240*03ce13f7SAndroid Build Coastguard Worker} 241*03ce13f7SAndroid Build Coastguard Worker 242*03ce13f7SAndroid Build Coastguard Workerfunc (t Test) byName(s Strings) []namedIndex { 243*03ce13f7SAndroid Build Coastguard Worker out := make([]namedIndex, len(t.children)) 244*03ce13f7SAndroid Build Coastguard Worker for id, idx := range t.indices { 245*03ce13f7SAndroid Build Coastguard Worker out[idx] = namedIndex{s.s[id], idx} 246*03ce13f7SAndroid Build Coastguard Worker } 247*03ce13f7SAndroid Build Coastguard Worker sort.Slice(out, func(i, j int) bool { return out[i].name < out[j].name }) 248*03ce13f7SAndroid Build Coastguard Worker return out 249*03ce13f7SAndroid Build Coastguard Worker} 250*03ce13f7SAndroid Build Coastguard Worker 251*03ce13f7SAndroid Build Coastguard Workerfunc (t Test) String(s Strings) string { 252*03ce13f7SAndroid Build Coastguard Worker sb := strings.Builder{} 253*03ce13f7SAndroid Build Coastguard Worker for i, n := range t.byName(s) { 254*03ce13f7SAndroid Build Coastguard Worker child := t.children[n.idx] 255*03ce13f7SAndroid Build Coastguard Worker if i > 0 { 256*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(" ") 257*03ce13f7SAndroid Build Coastguard Worker } 258*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(n.name) 259*03ce13f7SAndroid Build Coastguard Worker if len(child.children) > 0 { 260*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(fmt.Sprintf(":%v", child.String(s))) 261*03ce13f7SAndroid Build Coastguard Worker } 262*03ce13f7SAndroid Build Coastguard Worker } 263*03ce13f7SAndroid Build Coastguard Worker return "{" + sb.String() + "}" 264*03ce13f7SAndroid Build Coastguard Worker} 265*03ce13f7SAndroid Build Coastguard Worker 266*03ce13f7SAndroid Build Coastguard Worker// TestCoverage holds the coverage information for a deqp test group / leaf. 267*03ce13f7SAndroid Build Coastguard Worker// For example: 268*03ce13f7SAndroid Build Coastguard Worker// The deqp test group may hold spans that are common for all children, and may 269*03ce13f7SAndroid Build Coastguard Worker// also optionally hold child nodes that describe coverage that differs per 270*03ce13f7SAndroid Build Coastguard Worker// child test. 271*03ce13f7SAndroid Build Coastguard Workertype TestCoverage struct { 272*03ce13f7SAndroid Build Coastguard Worker Spans SpanSet 273*03ce13f7SAndroid Build Coastguard Worker Group *SpanGroupID 274*03ce13f7SAndroid Build Coastguard Worker Children TestCoverageMap 275*03ce13f7SAndroid Build Coastguard Worker} 276*03ce13f7SAndroid Build Coastguard Worker 277*03ce13f7SAndroid Build Coastguard Workerfunc (tc TestCoverage) String(t *Test, s Strings) string { 278*03ce13f7SAndroid Build Coastguard Worker sb := strings.Builder{} 279*03ce13f7SAndroid Build Coastguard Worker sb.WriteString("{") 280*03ce13f7SAndroid Build Coastguard Worker if len(tc.Spans) > 0 { 281*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(tc.Spans.String()) 282*03ce13f7SAndroid Build Coastguard Worker } 283*03ce13f7SAndroid Build Coastguard Worker if tc.Group != nil { 284*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(" <") 285*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(fmt.Sprintf("%v", *tc.Group)) 286*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(">") 287*03ce13f7SAndroid Build Coastguard Worker } 288*03ce13f7SAndroid Build Coastguard Worker if len(tc.Children) > 0 { 289*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(" ") 290*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(tc.Children.String(t, s)) 291*03ce13f7SAndroid Build Coastguard Worker } 292*03ce13f7SAndroid Build Coastguard Worker sb.WriteString("}") 293*03ce13f7SAndroid Build Coastguard Worker return sb.String() 294*03ce13f7SAndroid Build Coastguard Worker} 295*03ce13f7SAndroid Build Coastguard Worker 296*03ce13f7SAndroid Build Coastguard Worker// deletable returns true if the TestCoverage provides no data. 297*03ce13f7SAndroid Build Coastguard Workerfunc (tc TestCoverage) deletable() bool { 298*03ce13f7SAndroid Build Coastguard Worker return len(tc.Spans) == 0 && tc.Group == nil && len(tc.Children) == 0 299*03ce13f7SAndroid Build Coastguard Worker} 300*03ce13f7SAndroid Build Coastguard Worker 301*03ce13f7SAndroid Build Coastguard Worker// TestCoverageMap is a map of TestIndex to *TestCoverage. 302*03ce13f7SAndroid Build Coastguard Workertype TestCoverageMap map[TestIndex]*TestCoverage 303*03ce13f7SAndroid Build Coastguard Worker 304*03ce13f7SAndroid Build Coastguard Worker// traverse performs a depth first traversal of the TestCoverage tree. 305*03ce13f7SAndroid Build Coastguard Workerfunc (tcm TestCoverageMap) traverse(cb func(*TestCoverage)) { 306*03ce13f7SAndroid Build Coastguard Worker for _, tc := range tcm { 307*03ce13f7SAndroid Build Coastguard Worker cb(tc) 308*03ce13f7SAndroid Build Coastguard Worker tc.Children.traverse(cb) 309*03ce13f7SAndroid Build Coastguard Worker } 310*03ce13f7SAndroid Build Coastguard Worker} 311*03ce13f7SAndroid Build Coastguard Worker 312*03ce13f7SAndroid Build Coastguard Workerfunc (tcm TestCoverageMap) String(t *Test, s Strings) string { 313*03ce13f7SAndroid Build Coastguard Worker sb := strings.Builder{} 314*03ce13f7SAndroid Build Coastguard Worker for _, n := range t.byName(s) { 315*03ce13f7SAndroid Build Coastguard Worker if child, ok := tcm[n.idx]; ok { 316*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(fmt.Sprintf("\n%v: %v", n.name, child.String(&t.children[n.idx], s))) 317*03ce13f7SAndroid Build Coastguard Worker } 318*03ce13f7SAndroid Build Coastguard Worker } 319*03ce13f7SAndroid Build Coastguard Worker if sb.Len() > 0 { 320*03ce13f7SAndroid Build Coastguard Worker sb.WriteString("\n") 321*03ce13f7SAndroid Build Coastguard Worker } 322*03ce13f7SAndroid Build Coastguard Worker return indent(sb.String()) 323*03ce13f7SAndroid Build Coastguard Worker} 324*03ce13f7SAndroid Build Coastguard Worker 325*03ce13f7SAndroid Build Coastguard Workerfunc newTestCoverage() *TestCoverage { 326*03ce13f7SAndroid Build Coastguard Worker return &TestCoverage{ 327*03ce13f7SAndroid Build Coastguard Worker Children: TestCoverageMap{}, 328*03ce13f7SAndroid Build Coastguard Worker Spans: SpanSet{}, 329*03ce13f7SAndroid Build Coastguard Worker } 330*03ce13f7SAndroid Build Coastguard Worker} 331*03ce13f7SAndroid Build Coastguard Worker 332*03ce13f7SAndroid Build Coastguard Workerfunc (tcm TestCoverageMap) index(idx TestIndex) *TestCoverage { 333*03ce13f7SAndroid Build Coastguard Worker tc, ok := tcm[idx] 334*03ce13f7SAndroid Build Coastguard Worker if !ok { 335*03ce13f7SAndroid Build Coastguard Worker tc = newTestCoverage() 336*03ce13f7SAndroid Build Coastguard Worker tcm[idx] = tc 337*03ce13f7SAndroid Build Coastguard Worker } 338*03ce13f7SAndroid Build Coastguard Worker return tc 339*03ce13f7SAndroid Build Coastguard Worker} 340*03ce13f7SAndroid Build Coastguard Worker 341*03ce13f7SAndroid Build Coastguard Worker// SpanID is an identifier of a span in a Tree. 342*03ce13f7SAndroid Build Coastguard Workertype SpanID int 343*03ce13f7SAndroid Build Coastguard Worker 344*03ce13f7SAndroid Build Coastguard Worker// SpanSet is a set of SpanIDs. 345*03ce13f7SAndroid Build Coastguard Workertype SpanSet map[SpanID]struct{} 346*03ce13f7SAndroid Build Coastguard Worker 347*03ce13f7SAndroid Build Coastguard Worker// SpanIDList is a list of SpanIDs 348*03ce13f7SAndroid Build Coastguard Workertype SpanIDList []SpanID 349*03ce13f7SAndroid Build Coastguard Worker 350*03ce13f7SAndroid Build Coastguard Worker// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0. 351*03ce13f7SAndroid Build Coastguard Workerfunc (l SpanIDList) Compare(o SpanIDList) int { 352*03ce13f7SAndroid Build Coastguard Worker switch { 353*03ce13f7SAndroid Build Coastguard Worker case len(l) < len(o): 354*03ce13f7SAndroid Build Coastguard Worker return -1 355*03ce13f7SAndroid Build Coastguard Worker case len(l) > len(o): 356*03ce13f7SAndroid Build Coastguard Worker return 1 357*03ce13f7SAndroid Build Coastguard Worker } 358*03ce13f7SAndroid Build Coastguard Worker for i, a := range l { 359*03ce13f7SAndroid Build Coastguard Worker b := o[i] 360*03ce13f7SAndroid Build Coastguard Worker switch { 361*03ce13f7SAndroid Build Coastguard Worker case a < b: 362*03ce13f7SAndroid Build Coastguard Worker return -1 363*03ce13f7SAndroid Build Coastguard Worker case a > b: 364*03ce13f7SAndroid Build Coastguard Worker return 1 365*03ce13f7SAndroid Build Coastguard Worker } 366*03ce13f7SAndroid Build Coastguard Worker } 367*03ce13f7SAndroid Build Coastguard Worker return 0 368*03ce13f7SAndroid Build Coastguard Worker} 369*03ce13f7SAndroid Build Coastguard Worker 370*03ce13f7SAndroid Build Coastguard Worker// List returns the full list of sorted span ids. 371*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) List() SpanIDList { 372*03ce13f7SAndroid Build Coastguard Worker out := make(SpanIDList, 0, len(s)) 373*03ce13f7SAndroid Build Coastguard Worker for span := range s { 374*03ce13f7SAndroid Build Coastguard Worker out = append(out, span) 375*03ce13f7SAndroid Build Coastguard Worker } 376*03ce13f7SAndroid Build Coastguard Worker sort.Slice(out, func(i, j int) bool { return out[i] < out[j] }) 377*03ce13f7SAndroid Build Coastguard Worker return out 378*03ce13f7SAndroid Build Coastguard Worker} 379*03ce13f7SAndroid Build Coastguard Worker 380*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) String() string { 381*03ce13f7SAndroid Build Coastguard Worker sb := strings.Builder{} 382*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(`[`) 383*03ce13f7SAndroid Build Coastguard Worker l := s.List() 384*03ce13f7SAndroid Build Coastguard Worker for i, span := range l { 385*03ce13f7SAndroid Build Coastguard Worker if i > 0 { 386*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(`, `) 387*03ce13f7SAndroid Build Coastguard Worker } 388*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(fmt.Sprintf("%v", span)) 389*03ce13f7SAndroid Build Coastguard Worker } 390*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(`]`) 391*03ce13f7SAndroid Build Coastguard Worker return sb.String() 392*03ce13f7SAndroid Build Coastguard Worker} 393*03ce13f7SAndroid Build Coastguard Worker 394*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) contains(rhs SpanID) bool { 395*03ce13f7SAndroid Build Coastguard Worker _, found := s[rhs] 396*03ce13f7SAndroid Build Coastguard Worker return found 397*03ce13f7SAndroid Build Coastguard Worker} 398*03ce13f7SAndroid Build Coastguard Worker 399*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) containsAll(rhs SpanSet) bool { 400*03ce13f7SAndroid Build Coastguard Worker for span := range rhs { 401*03ce13f7SAndroid Build Coastguard Worker if !s.contains(span) { 402*03ce13f7SAndroid Build Coastguard Worker return false 403*03ce13f7SAndroid Build Coastguard Worker } 404*03ce13f7SAndroid Build Coastguard Worker } 405*03ce13f7SAndroid Build Coastguard Worker return true 406*03ce13f7SAndroid Build Coastguard Worker} 407*03ce13f7SAndroid Build Coastguard Worker 408*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) remove(rhs SpanID) SpanSet { 409*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(s)) 410*03ce13f7SAndroid Build Coastguard Worker for span := range s { 411*03ce13f7SAndroid Build Coastguard Worker if span != rhs { 412*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 413*03ce13f7SAndroid Build Coastguard Worker } 414*03ce13f7SAndroid Build Coastguard Worker } 415*03ce13f7SAndroid Build Coastguard Worker return out 416*03ce13f7SAndroid Build Coastguard Worker} 417*03ce13f7SAndroid Build Coastguard Worker 418*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) removeAll(rhs SpanSet) SpanSet { 419*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(s)) 420*03ce13f7SAndroid Build Coastguard Worker for span := range s { 421*03ce13f7SAndroid Build Coastguard Worker if _, found := rhs[span]; !found { 422*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 423*03ce13f7SAndroid Build Coastguard Worker } 424*03ce13f7SAndroid Build Coastguard Worker } 425*03ce13f7SAndroid Build Coastguard Worker return out 426*03ce13f7SAndroid Build Coastguard Worker} 427*03ce13f7SAndroid Build Coastguard Worker 428*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) add(rhs SpanID) SpanSet { 429*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(s)+1) 430*03ce13f7SAndroid Build Coastguard Worker for span := range s { 431*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 432*03ce13f7SAndroid Build Coastguard Worker } 433*03ce13f7SAndroid Build Coastguard Worker out[rhs] = struct{}{} 434*03ce13f7SAndroid Build Coastguard Worker return out 435*03ce13f7SAndroid Build Coastguard Worker} 436*03ce13f7SAndroid Build Coastguard Worker 437*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) addAll(rhs SpanSet) SpanSet { 438*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(s)+len(rhs)) 439*03ce13f7SAndroid Build Coastguard Worker for span := range s { 440*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 441*03ce13f7SAndroid Build Coastguard Worker } 442*03ce13f7SAndroid Build Coastguard Worker for span := range rhs { 443*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 444*03ce13f7SAndroid Build Coastguard Worker } 445*03ce13f7SAndroid Build Coastguard Worker return out 446*03ce13f7SAndroid Build Coastguard Worker} 447*03ce13f7SAndroid Build Coastguard Worker 448*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) invert(rhs SpanID) SpanSet { 449*03ce13f7SAndroid Build Coastguard Worker if s.contains(rhs) { 450*03ce13f7SAndroid Build Coastguard Worker return s.remove(rhs) 451*03ce13f7SAndroid Build Coastguard Worker } 452*03ce13f7SAndroid Build Coastguard Worker return s.add(rhs) 453*03ce13f7SAndroid Build Coastguard Worker} 454*03ce13f7SAndroid Build Coastguard Worker 455*03ce13f7SAndroid Build Coastguard Workerfunc (s SpanSet) invertAll(rhs SpanSet) SpanSet { 456*03ce13f7SAndroid Build Coastguard Worker out := make(SpanSet, len(s)+len(rhs)) 457*03ce13f7SAndroid Build Coastguard Worker for span := range s { 458*03ce13f7SAndroid Build Coastguard Worker if !rhs.contains(span) { 459*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 460*03ce13f7SAndroid Build Coastguard Worker } 461*03ce13f7SAndroid Build Coastguard Worker } 462*03ce13f7SAndroid Build Coastguard Worker for span := range rhs { 463*03ce13f7SAndroid Build Coastguard Worker if !s.contains(span) { 464*03ce13f7SAndroid Build Coastguard Worker out[span] = struct{}{} 465*03ce13f7SAndroid Build Coastguard Worker } 466*03ce13f7SAndroid Build Coastguard Worker } 467*03ce13f7SAndroid Build Coastguard Worker return out 468*03ce13f7SAndroid Build Coastguard Worker} 469*03ce13f7SAndroid Build Coastguard Worker 470*03ce13f7SAndroid Build Coastguard Worker// SpanGroupID is an identifier of a SpanGroup. 471*03ce13f7SAndroid Build Coastguard Workertype SpanGroupID int 472*03ce13f7SAndroid Build Coastguard Worker 473*03ce13f7SAndroid Build Coastguard Worker// SpanGroup holds a number of spans, potentially extending from another 474*03ce13f7SAndroid Build Coastguard Worker// SpanGroup. 475*03ce13f7SAndroid Build Coastguard Workertype SpanGroup struct { 476*03ce13f7SAndroid Build Coastguard Worker Spans SpanSet 477*03ce13f7SAndroid Build Coastguard Worker Extend *SpanGroupID 478*03ce13f7SAndroid Build Coastguard Worker} 479*03ce13f7SAndroid Build Coastguard Worker 480*03ce13f7SAndroid Build Coastguard Workerfunc newSpanGroup() SpanGroup { 481*03ce13f7SAndroid Build Coastguard Worker return SpanGroup{Spans: SpanSet{}} 482*03ce13f7SAndroid Build Coastguard Worker} 483*03ce13f7SAndroid Build Coastguard Worker 484*03ce13f7SAndroid Build Coastguard Workerfunc indent(s string) string { 485*03ce13f7SAndroid Build Coastguard Worker return strings.TrimSuffix(strings.ReplaceAll(s, "\n", "\n "), " ") 486*03ce13f7SAndroid Build Coastguard Worker} 487