xref: /aosp_15_r20/external/swiftshader/tests/regres/cov/tree.go (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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