1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18	"bytes"
19	"fmt"
20	"os"
21	"strings"
22	"testing"
23
24	"android/soong/tools/compliance"
25)
26
27func TestMain(m *testing.M) {
28	// Change into the parent directory before running the tests
29	// so they can find the testdata directory.
30	if err := os.Chdir(".."); err != nil {
31		fmt.Printf("failed to change to testdata directory: %s\n", err)
32		os.Exit(1)
33	}
34	os.Exit(m.Run())
35}
36
37func Test_plaintext(t *testing.T) {
38	tests := []struct {
39		condition   string
40		name        string
41		outDir      string
42		roots       []string
43		ctx         context
44		expectedOut []string
45	}{
46		{
47			condition: "firstparty",
48			name:      "apex",
49			roots:     []string{"highest.apex.meta_lic"},
50			expectedOut: []string{
51				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
52				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic static",
53				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/lib/libb.so.meta_lic dynamic",
54				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/lib/libd.so.meta_lic dynamic",
55				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin1.meta_lic static",
56				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin2.meta_lic static",
57				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
58				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libb.so.meta_lic static",
59			},
60		},
61		{
62			condition: "firstparty",
63			name:      "apex_trimmed",
64			roots:     []string{"highest.apex.meta_lic"},
65			ctx:       context{stripPrefix: []string{"testdata/firstparty/"}},
66			expectedOut: []string{
67				"bin/bin1.meta_lic lib/liba.so.meta_lic static",
68				"bin/bin1.meta_lic lib/libc.a.meta_lic static",
69				"bin/bin2.meta_lic lib/libb.so.meta_lic dynamic",
70				"bin/bin2.meta_lic lib/libd.so.meta_lic dynamic",
71				"highest.apex.meta_lic bin/bin1.meta_lic static",
72				"highest.apex.meta_lic bin/bin2.meta_lic static",
73				"highest.apex.meta_lic lib/liba.so.meta_lic static",
74				"highest.apex.meta_lic lib/libb.so.meta_lic static",
75			},
76		},
77		{
78			condition: "firstparty",
79			name:      "apex_trimmed_labelled",
80			roots:     []string{"highest.apex.meta_lic"},
81			ctx:       context{stripPrefix: []string{"testdata/firstparty/"}, labelConditions: true},
82			expectedOut: []string{
83				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice static",
84				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice static",
85				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:notice dynamic",
86				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic",
87				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
88				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static",
89				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice static",
90				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice static",
91			},
92		},
93		{
94			condition: "firstparty",
95			name:      "container",
96			roots:     []string{"container.zip.meta_lic"},
97			expectedOut: []string{
98				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
99				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic static",
100				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/lib/libb.so.meta_lic dynamic",
101				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/lib/libd.so.meta_lic dynamic",
102				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin1.meta_lic static",
103				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin2.meta_lic static",
104				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
105				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libb.so.meta_lic static",
106			},
107		},
108		{
109			condition: "firstparty",
110			name:      "application",
111			roots:     []string{"application.meta_lic"},
112			expectedOut: []string{
113				"testdata/firstparty/application.meta_lic testdata/firstparty/bin/bin3.meta_lic toolchain",
114				"testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
115				"testdata/firstparty/application.meta_lic testdata/firstparty/lib/libb.so.meta_lic dynamic",
116			},
117		},
118		{
119			condition: "firstparty",
120			name:      "binary",
121			roots:     []string{"bin/bin1.meta_lic"},
122			expectedOut: []string{
123				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic static",
124				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic static",
125			},
126		},
127		{
128			condition:   "firstparty",
129			name:        "library",
130			roots:       []string{"lib/libd.so.meta_lic"},
131			expectedOut: []string{},
132		},
133		{
134			condition: "notice",
135			name:      "apex",
136			roots:     []string{"highest.apex.meta_lic"},
137			expectedOut: []string{
138				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic static",
139				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic static",
140				"testdata/notice/bin/bin2.meta_lic testdata/notice/lib/libb.so.meta_lic dynamic",
141				"testdata/notice/bin/bin2.meta_lic testdata/notice/lib/libd.so.meta_lic dynamic",
142				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin1.meta_lic static",
143				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin2.meta_lic static",
144				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/liba.so.meta_lic static",
145				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libb.so.meta_lic static",
146			},
147		},
148		{
149			condition: "notice",
150			name:      "apex_trimmed",
151			roots:     []string{"highest.apex.meta_lic"},
152			ctx:       context{stripPrefix: []string{"testdata/notice/"}},
153			expectedOut: []string{
154				"bin/bin1.meta_lic lib/liba.so.meta_lic static",
155				"bin/bin1.meta_lic lib/libc.a.meta_lic static",
156				"bin/bin2.meta_lic lib/libb.so.meta_lic dynamic",
157				"bin/bin2.meta_lic lib/libd.so.meta_lic dynamic",
158				"highest.apex.meta_lic bin/bin1.meta_lic static",
159				"highest.apex.meta_lic bin/bin2.meta_lic static",
160				"highest.apex.meta_lic lib/liba.so.meta_lic static",
161				"highest.apex.meta_lic lib/libb.so.meta_lic static",
162			},
163		},
164		{
165			condition: "notice",
166			name:      "apex_trimmed_labelled",
167			roots:     []string{"highest.apex.meta_lic"},
168			ctx:       context{stripPrefix: []string{"testdata/notice/"}, labelConditions: true},
169			expectedOut: []string{
170				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice static",
171				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice static",
172				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:notice dynamic",
173				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic",
174				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
175				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static",
176				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice static",
177				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice static",
178			},
179		},
180		{
181			condition: "notice",
182			name:      "container",
183			roots:     []string{"container.zip.meta_lic"},
184			expectedOut: []string{
185				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic static",
186				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic static",
187				"testdata/notice/bin/bin2.meta_lic testdata/notice/lib/libb.so.meta_lic dynamic",
188				"testdata/notice/bin/bin2.meta_lic testdata/notice/lib/libd.so.meta_lic dynamic",
189				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin1.meta_lic static",
190				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin2.meta_lic static",
191				"testdata/notice/container.zip.meta_lic testdata/notice/lib/liba.so.meta_lic static",
192				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libb.so.meta_lic static",
193			},
194		},
195		{
196			condition: "notice",
197			name:      "application",
198			roots:     []string{"application.meta_lic"},
199			expectedOut: []string{
200				"testdata/notice/application.meta_lic testdata/notice/bin/bin3.meta_lic toolchain",
201				"testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic static",
202				"testdata/notice/application.meta_lic testdata/notice/lib/libb.so.meta_lic dynamic",
203			},
204		},
205		{
206			condition: "notice",
207			name:      "binary",
208			roots:     []string{"bin/bin1.meta_lic"},
209			expectedOut: []string{
210				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic static",
211				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic static",
212			},
213		},
214		{
215			condition:   "notice",
216			name:        "library",
217			roots:       []string{"lib/libd.so.meta_lic"},
218			expectedOut: []string{},
219		},
220		{
221			condition: "reciprocal",
222			name:      "apex",
223			roots:     []string{"highest.apex.meta_lic"},
224			expectedOut: []string{
225				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
226				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic static",
227				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/lib/libb.so.meta_lic dynamic",
228				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/lib/libd.so.meta_lic dynamic",
229				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin1.meta_lic static",
230				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin2.meta_lic static",
231				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
232				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libb.so.meta_lic static",
233			},
234		},
235		{
236			condition: "reciprocal",
237			name:      "apex_trimmed",
238			roots:     []string{"highest.apex.meta_lic"},
239			ctx:       context{stripPrefix: []string{"testdata/reciprocal/"}},
240			expectedOut: []string{
241				"bin/bin1.meta_lic lib/liba.so.meta_lic static",
242				"bin/bin1.meta_lic lib/libc.a.meta_lic static",
243				"bin/bin2.meta_lic lib/libb.so.meta_lic dynamic",
244				"bin/bin2.meta_lic lib/libd.so.meta_lic dynamic",
245				"highest.apex.meta_lic bin/bin1.meta_lic static",
246				"highest.apex.meta_lic bin/bin2.meta_lic static",
247				"highest.apex.meta_lic lib/liba.so.meta_lic static",
248				"highest.apex.meta_lic lib/libb.so.meta_lic static",
249			},
250		},
251		{
252			condition: "reciprocal",
253			name:      "apex_trimmed_labelled",
254			roots:     []string{"highest.apex.meta_lic"},
255			ctx:       context{stripPrefix: []string{"testdata/reciprocal/"}, labelConditions: true},
256			expectedOut: []string{
257				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:reciprocal static",
258				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal static",
259				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:notice dynamic",
260				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic",
261				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
262				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static",
263				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:reciprocal static",
264				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice static",
265			},
266		},
267		{
268			condition: "reciprocal",
269			name:      "container",
270			roots:     []string{"container.zip.meta_lic"},
271			expectedOut: []string{
272				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
273				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic static",
274				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/lib/libb.so.meta_lic dynamic",
275				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/lib/libd.so.meta_lic dynamic",
276				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin1.meta_lic static",
277				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin2.meta_lic static",
278				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
279				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libb.so.meta_lic static",
280			},
281		},
282		{
283			condition: "reciprocal",
284			name:      "application",
285			roots:     []string{"application.meta_lic"},
286			expectedOut: []string{
287				"testdata/reciprocal/application.meta_lic testdata/reciprocal/bin/bin3.meta_lic toolchain",
288				"testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
289				"testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/libb.so.meta_lic dynamic",
290			},
291		},
292		{
293			condition: "reciprocal",
294			name:      "binary",
295			roots:     []string{"bin/bin1.meta_lic"},
296			expectedOut: []string{
297				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic static",
298				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic static",
299			},
300		},
301		{
302			condition:   "reciprocal",
303			name:        "library",
304			roots:       []string{"lib/libd.so.meta_lic"},
305			expectedOut: []string{},
306		},
307		{
308			condition: "restricted",
309			name:      "apex",
310			roots:     []string{"highest.apex.meta_lic"},
311			expectedOut: []string{
312				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
313				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic static",
314				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic dynamic",
315				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic dynamic",
316				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic static",
317				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic static",
318				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
319				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic static",
320			},
321		},
322		{
323			condition: "restricted",
324			name:      "apex_trimmed",
325			roots:     []string{"highest.apex.meta_lic"},
326			ctx:       context{stripPrefix: []string{"testdata/restricted/"}},
327			expectedOut: []string{
328				"bin/bin1.meta_lic lib/liba.so.meta_lic static",
329				"bin/bin1.meta_lic lib/libc.a.meta_lic static",
330				"bin/bin2.meta_lic lib/libb.so.meta_lic dynamic",
331				"bin/bin2.meta_lic lib/libd.so.meta_lic dynamic",
332				"highest.apex.meta_lic bin/bin1.meta_lic static",
333				"highest.apex.meta_lic bin/bin2.meta_lic static",
334				"highest.apex.meta_lic lib/liba.so.meta_lic static",
335				"highest.apex.meta_lic lib/libb.so.meta_lic static",
336			},
337		},
338		{
339			condition: "restricted",
340			name:      "apex_trimmed_labelled",
341			roots:     []string{"highest.apex.meta_lic"},
342			ctx:       context{stripPrefix: []string{"testdata/restricted/"}, labelConditions: true},
343			expectedOut: []string{
344				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted_if_statically_linked static",
345				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal static",
346				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted dynamic",
347				"bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic",
348				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
349				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static",
350				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted_if_statically_linked static",
351				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted static",
352			},
353		},
354		{
355			condition: "restricted",
356			name:      "container",
357			roots:     []string{"container.zip.meta_lic"},
358			expectedOut: []string{
359				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
360				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic static",
361				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic dynamic",
362				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic dynamic",
363				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic static",
364				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic static",
365				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
366				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic static",
367			},
368		},
369		{
370			condition: "restricted",
371			name:      "application",
372			roots:     []string{"application.meta_lic"},
373			expectedOut: []string{
374				"testdata/restricted/application.meta_lic testdata/restricted/bin/bin3.meta_lic toolchain",
375				"testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
376				"testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic dynamic",
377			},
378		},
379		{
380			condition: "restricted",
381			name:      "binary",
382			roots:     []string{"bin/bin1.meta_lic"},
383			expectedOut: []string{
384				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic static",
385				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic static",
386			},
387		},
388		{
389			condition:   "restricted",
390			name:        "library",
391			roots:       []string{"lib/libd.so.meta_lic"},
392			expectedOut: []string{},
393		},
394		{
395			condition: "proprietary",
396			name:      "apex",
397			roots:     []string{"highest.apex.meta_lic"},
398			expectedOut: []string{
399				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
400				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic static",
401				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic dynamic",
402				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic dynamic",
403				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin1.meta_lic static",
404				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic static",
405				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
406				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic static",
407			},
408		},
409		{
410			condition: "proprietary",
411			name:      "apex_trimmed",
412			roots:     []string{"highest.apex.meta_lic"},
413			ctx:       context{stripPrefix: []string{"testdata/proprietary/"}},
414			expectedOut: []string{
415				"bin/bin1.meta_lic lib/liba.so.meta_lic static",
416				"bin/bin1.meta_lic lib/libc.a.meta_lic static",
417				"bin/bin2.meta_lic lib/libb.so.meta_lic dynamic",
418				"bin/bin2.meta_lic lib/libd.so.meta_lic dynamic",
419				"highest.apex.meta_lic bin/bin1.meta_lic static",
420				"highest.apex.meta_lic bin/bin2.meta_lic static",
421				"highest.apex.meta_lic lib/liba.so.meta_lic static",
422				"highest.apex.meta_lic lib/libb.so.meta_lic static",
423			},
424		},
425		{
426			condition: "proprietary",
427			name:      "apex_trimmed_labelled",
428			roots:     []string{"highest.apex.meta_lic"},
429			ctx:       context{stripPrefix: []string{"testdata/proprietary/"}, labelConditions: true},
430			expectedOut: []string{
431				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary static",
432				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:by_exception_only:proprietary static",
433				"bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted dynamic",
434				"bin/bin2.meta_lic:by_exception_only:proprietary lib/libd.so.meta_lic:notice dynamic",
435				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static",
436				"highest.apex.meta_lic:notice bin/bin2.meta_lic:by_exception_only:proprietary static",
437				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary static",
438				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted static",
439			},
440		},
441		{
442			condition: "proprietary",
443			name:      "container",
444			roots:     []string{"container.zip.meta_lic"},
445			expectedOut: []string{
446				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
447				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic static",
448				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic dynamic",
449				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic dynamic",
450				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin1.meta_lic static",
451				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic static",
452				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
453				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic static",
454			},
455		},
456		{
457			condition: "proprietary",
458			name:      "application",
459			roots:     []string{"application.meta_lic"},
460			expectedOut: []string{
461				"testdata/proprietary/application.meta_lic testdata/proprietary/bin/bin3.meta_lic toolchain",
462				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
463				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic dynamic",
464			},
465		},
466		{
467			condition: "proprietary",
468			name:      "binary",
469			roots:     []string{"bin/bin1.meta_lic"},
470			expectedOut: []string{
471				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic static",
472				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic static",
473			},
474		},
475		{
476			condition:   "proprietary",
477			name:        "library",
478			roots:       []string{"lib/libd.so.meta_lic"},
479			expectedOut: []string{},
480		},
481	}
482	for _, tt := range tests {
483		t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
484			expectedOut := &bytes.Buffer{}
485			for _, eo := range tt.expectedOut {
486				expectedOut.WriteString(eo)
487				expectedOut.WriteString("\n")
488			}
489
490			stdout := &bytes.Buffer{}
491			stderr := &bytes.Buffer{}
492
493			rootFiles := make([]string, 0, len(tt.roots))
494			for _, r := range tt.roots {
495				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
496			}
497			err := dumpGraph(&tt.ctx, stdout, stderr, compliance.GetFS(tt.outDir), rootFiles...)
498			if err != nil {
499				t.Fatalf("dumpgraph: error = %v, stderr = %v", err, stderr)
500				return
501			}
502			if stderr.Len() > 0 {
503				t.Errorf("dumpgraph: gotStderr = %v, want none", stderr)
504			}
505			out := stdout.String()
506			expected := expectedOut.String()
507			if out != expected {
508				outList := strings.Split(out, "\n")
509				expectedList := strings.Split(expected, "\n")
510				startLine := 0
511				for len(outList) > startLine && len(expectedList) > startLine && outList[startLine] == expectedList[startLine] {
512					startLine++
513				}
514				t.Errorf("listshare: gotStdout = %v, want %v, somewhere near line %d Stdout = %v, want %v",
515					out, expected, startLine+1, outList[startLine], expectedList[startLine])
516			}
517		})
518	}
519}
520
521type testContext struct {
522	nextNode int
523	nodes    map[string]string
524}
525
526type matcher interface {
527	matchString(*testContext) string
528	typeString() string
529}
530
531type targetMatcher struct {
532	target     string
533	conditions []string
534}
535
536func (tm *targetMatcher) matchString(ctx *testContext) string {
537	m := tm.target
538	if len(tm.conditions) > 0 {
539		m += "\\n" + strings.Join(tm.conditions, "\\n")
540	}
541	m = ctx.nodes[tm.target] + " [label=\"" + m + "\"];"
542	return m
543}
544
545func (tm *targetMatcher) typeString() string {
546	return "target"
547}
548
549type edgeMatcher struct {
550	target      string
551	dep         string
552	annotations []string
553}
554
555func (em *edgeMatcher) matchString(ctx *testContext) string {
556	return ctx.nodes[em.dep] + " -> " + ctx.nodes[em.target] + " [label=\"" + strings.Join(em.annotations, "\\n") + "\"];"
557}
558
559func (tm *edgeMatcher) typeString() string {
560	return "edge"
561}
562
563type getMatcher func(*testContext) matcher
564
565func matchTarget(target string, conditions ...string) getMatcher {
566	return func(ctx *testContext) matcher {
567		ctx.nodes[target] = fmt.Sprintf("n%d", ctx.nextNode)
568		ctx.nextNode++
569		return &targetMatcher{target, append([]string{}, conditions...)}
570	}
571}
572
573func matchEdge(target, dep string, annotations ...string) getMatcher {
574	return func(ctx *testContext) matcher {
575		if _, ok := ctx.nodes[target]; !ok {
576			panic(fmt.Errorf("no node for target %v in %v -> %v [label=\"%s\"];", target, dep, target, strings.Join(annotations, "\\n")))
577		}
578		if _, ok := ctx.nodes[dep]; !ok {
579			panic(fmt.Errorf("no node for dep %v in %v -> %v [label=\"%s\"];", target, dep, target, strings.Join(annotations, "\\n")))
580		}
581		return &edgeMatcher{target, dep, append([]string{}, annotations...)}
582	}
583}
584
585func Test_graphviz(t *testing.T) {
586	tests := []struct {
587		condition   string
588		name        string
589		outDir      string
590		roots       []string
591		ctx         context
592		expectedOut []getMatcher
593	}{
594		{
595			condition: "firstparty",
596			name:      "apex",
597			roots:     []string{"highest.apex.meta_lic"},
598			expectedOut: []getMatcher{
599				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
600				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
601				matchTarget("testdata/firstparty/highest.apex.meta_lic"),
602				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
603				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
604				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
605				matchTarget("testdata/firstparty/lib/libd.so.meta_lic"),
606				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
607				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.meta_lic", "static"),
608				matchEdge("testdata/firstparty/bin/bin2.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", "dynamic"),
609				matchEdge("testdata/firstparty/bin/bin2.meta_lic", "testdata/firstparty/lib/libd.so.meta_lic", "dynamic"),
610				matchEdge("testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/bin/bin1.meta_lic", "static"),
611				matchEdge("testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/bin/bin2.meta_lic", "static"),
612				matchEdge("testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
613				matchEdge("testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", "static"),
614			},
615		},
616		{
617			condition: "firstparty",
618			name:      "apex_trimmed",
619			roots:     []string{"highest.apex.meta_lic"},
620			ctx:       context{stripPrefix: []string{"testdata/firstparty/"}},
621			expectedOut: []getMatcher{
622				matchTarget("bin/bin1.meta_lic"),
623				matchTarget("bin/bin2.meta_lic"),
624				matchTarget("highest.apex.meta_lic"),
625				matchTarget("lib/liba.so.meta_lic"),
626				matchTarget("lib/libb.so.meta_lic"),
627				matchTarget("lib/libc.a.meta_lic"),
628				matchTarget("lib/libd.so.meta_lic"),
629				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
630				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
631				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
632				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
633				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
634				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
635				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
636				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
637			},
638		},
639		{
640			condition: "firstparty",
641			name:      "apex_trimmed_labelled",
642			roots:     []string{"highest.apex.meta_lic"},
643			ctx:       context{stripPrefix: []string{"testdata/firstparty/"}, labelConditions: true},
644			expectedOut: []getMatcher{
645				matchTarget("bin/bin1.meta_lic", "notice"),
646				matchTarget("bin/bin2.meta_lic", "notice"),
647				matchTarget("highest.apex.meta_lic", "notice"),
648				matchTarget("lib/liba.so.meta_lic", "notice"),
649				matchTarget("lib/libb.so.meta_lic", "notice"),
650				matchTarget("lib/libc.a.meta_lic", "notice"),
651				matchTarget("lib/libd.so.meta_lic", "notice"),
652				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
653				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
654				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
655				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
656				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
657				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
658				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
659				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
660			},
661		},
662		{
663			condition: "firstparty",
664			name:      "container",
665			roots:     []string{"container.zip.meta_lic"},
666			expectedOut: []getMatcher{
667				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
668				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
669				matchTarget("testdata/firstparty/container.zip.meta_lic"),
670				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
671				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
672				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
673				matchTarget("testdata/firstparty/lib/libd.so.meta_lic"),
674				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
675				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.meta_lic", "static"),
676				matchEdge("testdata/firstparty/bin/bin2.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", "dynamic"),
677				matchEdge("testdata/firstparty/bin/bin2.meta_lic", "testdata/firstparty/lib/libd.so.meta_lic", "dynamic"),
678				matchEdge("testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/bin/bin1.meta_lic", "static"),
679				matchEdge("testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/bin/bin2.meta_lic", "static"),
680				matchEdge("testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
681				matchEdge("testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", "static"),
682			},
683		},
684		{
685			condition: "firstparty",
686			name:      "application",
687			roots:     []string{"application.meta_lic"},
688			expectedOut: []getMatcher{
689				matchTarget("testdata/firstparty/application.meta_lic"),
690				matchTarget("testdata/firstparty/bin/bin3.meta_lic"),
691				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
692				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
693				matchEdge("testdata/firstparty/application.meta_lic", "testdata/firstparty/bin/bin3.meta_lic", "toolchain"),
694				matchEdge("testdata/firstparty/application.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
695				matchEdge("testdata/firstparty/application.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", "dynamic"),
696			},
697		},
698		{
699			condition: "firstparty",
700			name:      "binary",
701			roots:     []string{"bin/bin1.meta_lic"},
702			expectedOut: []getMatcher{
703				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
704				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
705				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
706				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", "static"),
707				matchEdge("testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.meta_lic", "static"),
708			},
709		},
710		{
711			condition:   "firstparty",
712			name:        "library",
713			roots:       []string{"lib/libd.so.meta_lic"},
714			expectedOut: []getMatcher{matchTarget("testdata/firstparty/lib/libd.so.meta_lic")},
715		},
716		{
717			condition: "notice",
718			name:      "apex",
719			roots:     []string{"highest.apex.meta_lic"},
720			expectedOut: []getMatcher{
721				matchTarget("testdata/notice/bin/bin1.meta_lic"),
722				matchTarget("testdata/notice/bin/bin2.meta_lic"),
723				matchTarget("testdata/notice/highest.apex.meta_lic"),
724				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
725				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
726				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
727				matchTarget("testdata/notice/lib/libd.so.meta_lic"),
728				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
729				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.meta_lic", "static"),
730				matchEdge("testdata/notice/bin/bin2.meta_lic", "testdata/notice/lib/libb.so.meta_lic", "dynamic"),
731				matchEdge("testdata/notice/bin/bin2.meta_lic", "testdata/notice/lib/libd.so.meta_lic", "dynamic"),
732				matchEdge("testdata/notice/highest.apex.meta_lic", "testdata/notice/bin/bin1.meta_lic", "static"),
733				matchEdge("testdata/notice/highest.apex.meta_lic", "testdata/notice/bin/bin2.meta_lic", "static"),
734				matchEdge("testdata/notice/highest.apex.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
735				matchEdge("testdata/notice/highest.apex.meta_lic", "testdata/notice/lib/libb.so.meta_lic", "static"),
736			},
737		},
738		{
739			condition: "notice",
740			name:      "apex_trimmed",
741			roots:     []string{"highest.apex.meta_lic"},
742			ctx:       context{stripPrefix: []string{"testdata/notice/"}},
743			expectedOut: []getMatcher{
744				matchTarget("bin/bin1.meta_lic"),
745				matchTarget("bin/bin2.meta_lic"),
746				matchTarget("highest.apex.meta_lic"),
747				matchTarget("lib/liba.so.meta_lic"),
748				matchTarget("lib/libb.so.meta_lic"),
749				matchTarget("lib/libc.a.meta_lic"),
750				matchTarget("lib/libd.so.meta_lic"),
751				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
752				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
753				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
754				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
755				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
756				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
757				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
758				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
759			},
760		},
761		{
762			condition: "notice",
763			name:      "apex_trimmed_labelled",
764			roots:     []string{"highest.apex.meta_lic"},
765			ctx:       context{stripPrefix: []string{"testdata/notice/"}, labelConditions: true},
766			expectedOut: []getMatcher{
767				matchTarget("bin/bin1.meta_lic", "notice"),
768				matchTarget("bin/bin2.meta_lic", "notice"),
769				matchTarget("highest.apex.meta_lic", "notice"),
770				matchTarget("lib/liba.so.meta_lic", "notice"),
771				matchTarget("lib/libb.so.meta_lic", "notice"),
772				matchTarget("lib/libc.a.meta_lic", "notice"),
773				matchTarget("lib/libd.so.meta_lic", "notice"),
774				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
775				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
776				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
777				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
778				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
779				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
780				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
781				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
782			},
783		},
784		{
785			condition: "notice",
786			name:      "container",
787			roots:     []string{"container.zip.meta_lic"},
788			expectedOut: []getMatcher{
789				matchTarget("testdata/notice/bin/bin1.meta_lic"),
790				matchTarget("testdata/notice/bin/bin2.meta_lic"),
791				matchTarget("testdata/notice/container.zip.meta_lic"),
792				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
793				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
794				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
795				matchTarget("testdata/notice/lib/libd.so.meta_lic"),
796				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
797				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.meta_lic", "static"),
798				matchEdge("testdata/notice/bin/bin2.meta_lic", "testdata/notice/lib/libb.so.meta_lic", "dynamic"),
799				matchEdge("testdata/notice/bin/bin2.meta_lic", "testdata/notice/lib/libd.so.meta_lic", "dynamic"),
800				matchEdge("testdata/notice/container.zip.meta_lic", "testdata/notice/bin/bin1.meta_lic", "static"),
801				matchEdge("testdata/notice/container.zip.meta_lic", "testdata/notice/bin/bin2.meta_lic", "static"),
802				matchEdge("testdata/notice/container.zip.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
803				matchEdge("testdata/notice/container.zip.meta_lic", "testdata/notice/lib/libb.so.meta_lic", "static"),
804			},
805		},
806		{
807			condition: "notice",
808			name:      "application",
809			roots:     []string{"application.meta_lic"},
810			expectedOut: []getMatcher{
811				matchTarget("testdata/notice/application.meta_lic"),
812				matchTarget("testdata/notice/bin/bin3.meta_lic"),
813				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
814				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
815				matchEdge("testdata/notice/application.meta_lic", "testdata/notice/bin/bin3.meta_lic", "toolchain"),
816				matchEdge("testdata/notice/application.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
817				matchEdge("testdata/notice/application.meta_lic", "testdata/notice/lib/libb.so.meta_lic", "dynamic"),
818			},
819		},
820		{
821			condition: "notice",
822			name:      "binary",
823			roots:     []string{"bin/bin1.meta_lic"},
824			expectedOut: []getMatcher{
825				matchTarget("testdata/notice/bin/bin1.meta_lic"),
826				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
827				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
828				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/liba.so.meta_lic", "static"),
829				matchEdge("testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.meta_lic", "static"),
830			},
831		},
832		{
833			condition:   "notice",
834			name:        "library",
835			roots:       []string{"lib/libd.so.meta_lic"},
836			expectedOut: []getMatcher{matchTarget("testdata/notice/lib/libd.so.meta_lic")},
837		},
838		{
839			condition: "reciprocal",
840			name:      "apex",
841			roots:     []string{"highest.apex.meta_lic"},
842			expectedOut: []getMatcher{
843				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
844				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
845				matchTarget("testdata/reciprocal/highest.apex.meta_lic"),
846				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
847				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
848				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
849				matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"),
850				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
851				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.meta_lic", "static"),
852				matchEdge("testdata/reciprocal/bin/bin2.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", "dynamic"),
853				matchEdge("testdata/reciprocal/bin/bin2.meta_lic", "testdata/reciprocal/lib/libd.so.meta_lic", "dynamic"),
854				matchEdge("testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/bin/bin1.meta_lic", "static"),
855				matchEdge("testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/bin/bin2.meta_lic", "static"),
856				matchEdge("testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
857				matchEdge("testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", "static"),
858			},
859		},
860		{
861			condition: "reciprocal",
862			name:      "apex_trimmed",
863			roots:     []string{"highest.apex.meta_lic"},
864			ctx:       context{stripPrefix: []string{"testdata/reciprocal/"}},
865			expectedOut: []getMatcher{
866				matchTarget("bin/bin1.meta_lic"),
867				matchTarget("bin/bin2.meta_lic"),
868				matchTarget("highest.apex.meta_lic"),
869				matchTarget("lib/liba.so.meta_lic"),
870				matchTarget("lib/libb.so.meta_lic"),
871				matchTarget("lib/libc.a.meta_lic"),
872				matchTarget("lib/libd.so.meta_lic"),
873				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
874				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
875				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
876				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
877				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
878				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
879				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
880				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
881			},
882		},
883		{
884			condition: "reciprocal",
885			name:      "apex_trimmed_labelled",
886			roots:     []string{"highest.apex.meta_lic"},
887			ctx:       context{stripPrefix: []string{"testdata/reciprocal/"}, labelConditions: true},
888			expectedOut: []getMatcher{
889				matchTarget("bin/bin1.meta_lic", "notice"),
890				matchTarget("bin/bin2.meta_lic", "notice"),
891				matchTarget("highest.apex.meta_lic", "notice"),
892				matchTarget("lib/liba.so.meta_lic", "reciprocal"),
893				matchTarget("lib/libb.so.meta_lic", "notice"),
894				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
895				matchTarget("lib/libd.so.meta_lic", "notice"),
896				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
897				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
898				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
899				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
900				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
901				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
902				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
903				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
904			},
905		},
906		{
907			condition: "reciprocal",
908			name:      "container",
909			roots:     []string{"container.zip.meta_lic"},
910			expectedOut: []getMatcher{
911				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
912				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
913				matchTarget("testdata/reciprocal/container.zip.meta_lic"),
914				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
915				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
916				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
917				matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"),
918				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
919				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.meta_lic", "static"),
920				matchEdge("testdata/reciprocal/bin/bin2.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", "dynamic"),
921				matchEdge("testdata/reciprocal/bin/bin2.meta_lic", "testdata/reciprocal/lib/libd.so.meta_lic", "dynamic"),
922				matchEdge("testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/bin/bin1.meta_lic", "static"),
923				matchEdge("testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/bin/bin2.meta_lic", "static"),
924				matchEdge("testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
925				matchEdge("testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", "static"),
926			},
927		},
928		{
929			condition: "reciprocal",
930			name:      "application",
931			roots:     []string{"application.meta_lic"},
932			expectedOut: []getMatcher{
933				matchTarget("testdata/reciprocal/application.meta_lic"),
934				matchTarget("testdata/reciprocal/bin/bin3.meta_lic"),
935				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
936				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
937				matchEdge("testdata/reciprocal/application.meta_lic", "testdata/reciprocal/bin/bin3.meta_lic", "toolchain"),
938				matchEdge("testdata/reciprocal/application.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
939				matchEdge("testdata/reciprocal/application.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", "dynamic"),
940			},
941		},
942		{
943			condition: "reciprocal",
944			name:      "binary",
945			roots:     []string{"bin/bin1.meta_lic"},
946			expectedOut: []getMatcher{
947				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
948				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
949				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
950				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", "static"),
951				matchEdge("testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.meta_lic", "static"),
952			},
953		},
954		{
955			condition:   "reciprocal",
956			name:        "library",
957			roots:       []string{"lib/libd.so.meta_lic"},
958			expectedOut: []getMatcher{matchTarget("testdata/reciprocal/lib/libd.so.meta_lic")},
959		},
960		{
961			condition: "restricted",
962			name:      "apex",
963			roots:     []string{"highest.apex.meta_lic"},
964			expectedOut: []getMatcher{
965				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
966				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
967				matchTarget("testdata/restricted/highest.apex.meta_lic"),
968				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
969				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
970				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
971				matchTarget("testdata/restricted/lib/libd.so.meta_lic"),
972				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
973				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", "static"),
974				matchEdge("testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "dynamic"),
975				matchEdge("testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/lib/libd.so.meta_lic", "dynamic"),
976				matchEdge("testdata/restricted/highest.apex.meta_lic", "testdata/restricted/bin/bin1.meta_lic", "static"),
977				matchEdge("testdata/restricted/highest.apex.meta_lic", "testdata/restricted/bin/bin2.meta_lic", "static"),
978				matchEdge("testdata/restricted/highest.apex.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
979				matchEdge("testdata/restricted/highest.apex.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "static"),
980			},
981		},
982		{
983			condition: "restricted",
984			name:      "apex_trimmed",
985			roots:     []string{"highest.apex.meta_lic"},
986			ctx:       context{stripPrefix: []string{"testdata/restricted/"}},
987			expectedOut: []getMatcher{
988				matchTarget("bin/bin1.meta_lic"),
989				matchTarget("bin/bin2.meta_lic"),
990				matchTarget("highest.apex.meta_lic"),
991				matchTarget("lib/liba.so.meta_lic"),
992				matchTarget("lib/libb.so.meta_lic"),
993				matchTarget("lib/libc.a.meta_lic"),
994				matchTarget("lib/libd.so.meta_lic"),
995				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
996				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
997				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
998				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
999				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
1000				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
1001				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
1002				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
1003			},
1004		},
1005		{
1006			condition: "restricted",
1007			name:      "apex_trimmed_labelled",
1008			roots:     []string{"highest.apex.meta_lic"},
1009			ctx:       context{stripPrefix: []string{"testdata/restricted/"}, labelConditions: true},
1010			expectedOut: []getMatcher{
1011				matchTarget("bin/bin1.meta_lic", "notice"),
1012				matchTarget("bin/bin2.meta_lic", "notice"),
1013				matchTarget("highest.apex.meta_lic", "notice"),
1014				matchTarget("lib/liba.so.meta_lic", "restricted_if_statically_linked"),
1015				matchTarget("lib/libb.so.meta_lic", "restricted"),
1016				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
1017				matchTarget("lib/libd.so.meta_lic", "notice"),
1018				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
1019				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
1020				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
1021				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
1022				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
1023				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
1024				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
1025				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
1026			},
1027		},
1028		{
1029			condition: "restricted",
1030			name:      "container",
1031			roots:     []string{"container.zip.meta_lic"},
1032			expectedOut: []getMatcher{
1033				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
1034				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
1035				matchTarget("testdata/restricted/container.zip.meta_lic"),
1036				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
1037				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
1038				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
1039				matchTarget("testdata/restricted/lib/libd.so.meta_lic"),
1040				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
1041				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", "static"),
1042				matchEdge("testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "dynamic"),
1043				matchEdge("testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/lib/libd.so.meta_lic", "dynamic"),
1044				matchEdge("testdata/restricted/container.zip.meta_lic", "testdata/restricted/bin/bin1.meta_lic", "static"),
1045				matchEdge("testdata/restricted/container.zip.meta_lic", "testdata/restricted/bin/bin2.meta_lic", "static"),
1046				matchEdge("testdata/restricted/container.zip.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
1047				matchEdge("testdata/restricted/container.zip.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "static"),
1048			},
1049		},
1050		{
1051			condition: "restricted",
1052			name:      "application",
1053			roots:     []string{"application.meta_lic"},
1054			expectedOut: []getMatcher{
1055				matchTarget("testdata/restricted/application.meta_lic"),
1056				matchTarget("testdata/restricted/bin/bin3.meta_lic"),
1057				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
1058				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
1059				matchEdge("testdata/restricted/application.meta_lic", "testdata/restricted/bin/bin3.meta_lic", "toolchain"),
1060				matchEdge("testdata/restricted/application.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
1061				matchEdge("testdata/restricted/application.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "dynamic"),
1062			},
1063		},
1064		{
1065			condition: "restricted",
1066			name:      "binary",
1067			roots:     []string{"bin/bin1.meta_lic"},
1068			expectedOut: []getMatcher{
1069				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
1070				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
1071				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
1072				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", "static"),
1073				matchEdge("testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", "static"),
1074			},
1075		},
1076		{
1077			condition:   "restricted",
1078			name:        "library",
1079			roots:       []string{"lib/libd.so.meta_lic"},
1080			expectedOut: []getMatcher{matchTarget("testdata/restricted/lib/libd.so.meta_lic")},
1081		},
1082		{
1083			condition: "proprietary",
1084			name:      "apex",
1085			roots:     []string{"highest.apex.meta_lic"},
1086			expectedOut: []getMatcher{
1087				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
1088				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
1089				matchTarget("testdata/proprietary/highest.apex.meta_lic"),
1090				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
1091				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
1092				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
1093				matchTarget("testdata/proprietary/lib/libd.so.meta_lic"),
1094				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1095				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/libc.a.meta_lic", "static"),
1096				matchEdge("testdata/proprietary/bin/bin2.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "dynamic"),
1097				matchEdge("testdata/proprietary/bin/bin2.meta_lic", "testdata/proprietary/lib/libd.so.meta_lic", "dynamic"),
1098				matchEdge("testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/bin/bin1.meta_lic", "static"),
1099				matchEdge("testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/bin/bin2.meta_lic", "static"),
1100				matchEdge("testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1101				matchEdge("testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "static"),
1102			},
1103		},
1104		{
1105			condition: "proprietary",
1106			name:      "apex_trimmed",
1107			roots:     []string{"highest.apex.meta_lic"},
1108			ctx:       context{stripPrefix: []string{"testdata/proprietary/"}},
1109			expectedOut: []getMatcher{
1110				matchTarget("bin/bin1.meta_lic"),
1111				matchTarget("bin/bin2.meta_lic"),
1112				matchTarget("highest.apex.meta_lic"),
1113				matchTarget("lib/liba.so.meta_lic"),
1114				matchTarget("lib/libb.so.meta_lic"),
1115				matchTarget("lib/libc.a.meta_lic"),
1116				matchTarget("lib/libd.so.meta_lic"),
1117				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
1118				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
1119				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
1120				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
1121				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
1122				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
1123				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
1124				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
1125			},
1126		},
1127		{
1128			condition: "proprietary",
1129			name:      "apex_trimmed_labelled",
1130			roots:     []string{"highest.apex.meta_lic"},
1131			ctx:       context{stripPrefix: []string{"testdata/proprietary/"}, labelConditions: true},
1132			expectedOut: []getMatcher{
1133				matchTarget("bin/bin1.meta_lic", "notice"),
1134				matchTarget("bin/bin2.meta_lic", "by_exception_only", "proprietary"),
1135				matchTarget("highest.apex.meta_lic", "notice"),
1136				matchTarget("lib/liba.so.meta_lic", "by_exception_only", "proprietary"),
1137				matchTarget("lib/libb.so.meta_lic", "restricted"),
1138				matchTarget("lib/libc.a.meta_lic", "by_exception_only", "proprietary"),
1139				matchTarget("lib/libd.so.meta_lic", "notice"),
1140				matchEdge("bin/bin1.meta_lic", "lib/liba.so.meta_lic", "static"),
1141				matchEdge("bin/bin1.meta_lic", "lib/libc.a.meta_lic", "static"),
1142				matchEdge("bin/bin2.meta_lic", "lib/libb.so.meta_lic", "dynamic"),
1143				matchEdge("bin/bin2.meta_lic", "lib/libd.so.meta_lic", "dynamic"),
1144				matchEdge("highest.apex.meta_lic", "bin/bin1.meta_lic", "static"),
1145				matchEdge("highest.apex.meta_lic", "bin/bin2.meta_lic", "static"),
1146				matchEdge("highest.apex.meta_lic", "lib/liba.so.meta_lic", "static"),
1147				matchEdge("highest.apex.meta_lic", "lib/libb.so.meta_lic", "static"),
1148			},
1149		},
1150		{
1151			condition: "proprietary",
1152			name:      "container",
1153			roots:     []string{"container.zip.meta_lic"},
1154			expectedOut: []getMatcher{
1155				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
1156				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
1157				matchTarget("testdata/proprietary/container.zip.meta_lic"),
1158				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
1159				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
1160				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
1161				matchTarget("testdata/proprietary/lib/libd.so.meta_lic"),
1162				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1163				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/libc.a.meta_lic", "static"),
1164				matchEdge("testdata/proprietary/bin/bin2.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "dynamic"),
1165				matchEdge("testdata/proprietary/bin/bin2.meta_lic", "testdata/proprietary/lib/libd.so.meta_lic", "dynamic"),
1166				matchEdge("testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/bin/bin1.meta_lic", "static"),
1167				matchEdge("testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/bin/bin2.meta_lic", "static"),
1168				matchEdge("testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1169				matchEdge("testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "static"),
1170			},
1171		},
1172		{
1173			condition: "proprietary",
1174			name:      "application",
1175			roots:     []string{"application.meta_lic"},
1176			expectedOut: []getMatcher{
1177				matchTarget("testdata/proprietary/application.meta_lic"),
1178				matchTarget("testdata/proprietary/bin/bin3.meta_lic"),
1179				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
1180				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
1181				matchEdge("testdata/proprietary/application.meta_lic", "testdata/proprietary/bin/bin3.meta_lic", "toolchain"),
1182				matchEdge("testdata/proprietary/application.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1183				matchEdge("testdata/proprietary/application.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "dynamic"),
1184			},
1185		},
1186		{
1187			condition: "proprietary",
1188			name:      "binary",
1189			roots:     []string{"bin/bin1.meta_lic"},
1190			expectedOut: []getMatcher{
1191				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
1192				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
1193				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
1194				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", "static"),
1195				matchEdge("testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/libc.a.meta_lic", "static"),
1196			},
1197		},
1198		{
1199			condition:   "proprietary",
1200			name:        "library",
1201			roots:       []string{"lib/libd.so.meta_lic"},
1202			expectedOut: []getMatcher{matchTarget("testdata/proprietary/lib/libd.so.meta_lic")},
1203		},
1204	}
1205	for _, tt := range tests {
1206		t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
1207			ctx := &testContext{0, make(map[string]string)}
1208
1209			expectedOut := &bytes.Buffer{}
1210			for _, eo := range tt.expectedOut {
1211				m := eo(ctx)
1212				expectedOut.WriteString(m.matchString(ctx))
1213				expectedOut.WriteString("\n")
1214			}
1215
1216			stdout := &bytes.Buffer{}
1217			stderr := &bytes.Buffer{}
1218
1219			rootFiles := make([]string, 0, len(tt.roots))
1220			for _, r := range tt.roots {
1221				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
1222			}
1223			tt.ctx.graphViz = true
1224			err := dumpGraph(&tt.ctx, stdout, stderr, compliance.GetFS(tt.outDir), rootFiles...)
1225			if err != nil {
1226				t.Fatalf("dumpgraph: error = %v, stderr = %v", err, stderr)
1227				return
1228			}
1229			if stderr.Len() > 0 {
1230				t.Errorf("dumpgraph: gotStderr = %v, want none", stderr)
1231			}
1232			outList := strings.Split(stdout.String(), "\n")
1233			outLine := 0
1234			if outList[outLine] != "strict digraph {" {
1235				t.Errorf("dumpgraph: got 1st line %v, want strict digraph {", outList[outLine])
1236			}
1237			outLine++
1238			if strings.HasPrefix(strings.TrimLeft(outList[outLine], " \t"), "rankdir") {
1239				outLine++
1240			}
1241			endOut := len(outList)
1242			for endOut > 0 && strings.TrimLeft(outList[endOut-1], " \t") == "" {
1243				endOut--
1244			}
1245			if outList[endOut-1] != "}" {
1246				t.Errorf("dumpgraph: got last line %v, want }", outList[endOut-1])
1247			}
1248			endOut--
1249			if strings.HasPrefix(strings.TrimLeft(outList[endOut-1], " \t"), "{rank=same") {
1250				endOut--
1251			}
1252			expectedList := strings.Split(expectedOut.String(), "\n")
1253			for len(expectedList) > 0 && expectedList[len(expectedList)-1] == "" {
1254				expectedList = expectedList[0 : len(expectedList)-1]
1255			}
1256			matchLine := 0
1257
1258			for outLine < endOut && matchLine < len(expectedList) && strings.TrimLeft(outList[outLine], " \t") == expectedList[matchLine] {
1259				outLine++
1260				matchLine++
1261			}
1262			if outLine < endOut || matchLine < len(expectedList) {
1263				if outLine >= endOut {
1264					t.Errorf("dumpgraph: missing lines at end of graph, want %d lines %v", len(expectedList)-matchLine, strings.Join(expectedList[matchLine:], "\n"))
1265				} else if matchLine >= len(expectedList) {
1266					t.Errorf("dumpgraph: unexpected lines at end of graph starting line %d, got %v, want nothing", outLine+1, strings.Join(outList[outLine:], "\n"))
1267				} else {
1268					t.Errorf("dumpgraph: at line %d, got %v, want %v", outLine+1, strings.Join(outList[outLine:], "\n"), strings.Join(expectedList[matchLine:], "\n"))
1269				}
1270			}
1271		})
1272	}
1273}
1274