xref: /aosp_15_r20/build/make/tools/compliance/policy_walk_test.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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 compliance
16
17import (
18	"bytes"
19	"fmt"
20	"os"
21	"strings"
22	"testing"
23)
24
25func TestMain(m *testing.M) {
26	// Change into the cmd directory before running the tests
27	// so they can find the testdata directory.
28	if err := os.Chdir("cmd"); err != nil {
29		fmt.Printf("failed to change to testdata directory: %s\n", err)
30		os.Exit(1)
31	}
32	os.Exit(m.Run())
33}
34
35func TestWalkResolutionsForCondition(t *testing.T) {
36	tests := []struct {
37		name                string
38		condition           LicenseConditionSet
39		roots               []string
40		edges               []annotated
41		expectedResolutions []res
42	}{
43		{
44			name:      "firstparty",
45			condition: ImpliesNotice,
46			roots:     []string{"apacheBin.meta_lic"},
47			edges: []annotated{
48				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
49			},
50			expectedResolutions: []res{
51				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
52				{"apacheBin.meta_lic", "apacheLib.meta_lic", "notice"},
53			},
54		},
55		{
56			name:      "notice",
57			condition: ImpliesNotice,
58			roots:     []string{"mitBin.meta_lic"},
59			edges: []annotated{
60				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
61			},
62			expectedResolutions: []res{
63				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
64				{"mitBin.meta_lic", "mitLib.meta_lic", "notice"},
65			},
66		},
67		{
68			name:      "fponlgplnotice",
69			condition: ImpliesNotice,
70			roots:     []string{"apacheBin.meta_lic"},
71			edges: []annotated{
72				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
73			},
74			expectedResolutions: []res{
75				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice|restricted_if_statically_linked"},
76				{"apacheBin.meta_lic", "lgplLib.meta_lic", "restricted_if_statically_linked"},
77			},
78		},
79		{
80			name:      "fponlgpldynamicnotice",
81			condition: ImpliesNotice,
82			roots:     []string{"apacheBin.meta_lic"},
83			edges: []annotated{
84				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
85			},
86			expectedResolutions: []res{
87				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
88			},
89		},
90		{
91			name:      "independentmodulenotice",
92			condition: ImpliesNotice,
93			roots:     []string{"apacheBin.meta_lic"},
94			edges: []annotated{
95				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
96			},
97			expectedResolutions: []res{
98				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
99			},
100		},
101		{
102			name:      "independentmodulerestricted",
103			condition: ImpliesRestricted,
104			roots:     []string{"apacheBin.meta_lic"},
105			edges: []annotated{
106				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
107			},
108			expectedResolutions: []res{},
109		},
110		{
111			name:      "independentmodulestaticnotice",
112			condition: ImpliesNotice,
113			roots:     []string{"apacheBin.meta_lic"},
114			edges: []annotated{
115				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
116			},
117			expectedResolutions: []res{
118				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"},
119				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "permissive"},
120			},
121		},
122		{
123			name:      "independentmodulestaticrestricted",
124			condition: ImpliesRestricted,
125			roots:     []string{"apacheBin.meta_lic"},
126			edges: []annotated{
127				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
128			},
129			expectedResolutions: []res{},
130		},
131		{
132			name:      "dependentmodulenotice",
133			condition: ImpliesNotice,
134			roots:     []string{"dependentModule.meta_lic"},
135			edges: []annotated{
136				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
137			},
138			expectedResolutions: []res{
139				{"dependentModule.meta_lic", "dependentModule.meta_lic", "notice"},
140			},
141		},
142		{
143			name:      "dependentmodulerestricted",
144			condition: ImpliesRestricted,
145			roots:     []string{"dependentModule.meta_lic"},
146			edges: []annotated{
147				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
148			},
149			expectedResolutions: []res{},
150		},
151		{
152			name:      "lgplonfpnotice",
153			condition: ImpliesNotice,
154			roots:     []string{"lgplBin.meta_lic"},
155			edges: []annotated{
156				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
157			},
158			expectedResolutions: []res{
159				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted_if_statically_linked"},
160				{"lgplBin.meta_lic", "apacheLib.meta_lic", "notice|restricted_if_statically_linked"},
161			},
162		},
163		{
164			name:      "lgplonfprestricted",
165			condition: ImpliesRestricted,
166			roots:     []string{"lgplBin.meta_lic"},
167			edges: []annotated{
168				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
169			},
170			expectedResolutions: []res{
171				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted_if_statically_linked"},
172				{"lgplBin.meta_lic", "apacheLib.meta_lic", "restricted_if_statically_linked"},
173			},
174		},
175		{
176			name:      "lgplonfpdynamicnotice",
177			condition: ImpliesNotice,
178			roots:     []string{"lgplBin.meta_lic"},
179			edges: []annotated{
180				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
181			},
182			expectedResolutions: []res{
183				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted_if_statically_linked"},
184			},
185		},
186		{
187			name:      "lgplonfpdynamicrestricted",
188			condition: ImpliesRestricted,
189			roots:     []string{"lgplBin.meta_lic"},
190			edges: []annotated{
191				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
192			},
193			expectedResolutions: []res{
194				{"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted_if_statically_linked"},
195			},
196		},
197		{
198			name:      "gplonfpnotice",
199			condition: ImpliesNotice,
200			roots:     []string{"gplBin.meta_lic"},
201			edges: []annotated{
202				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
203			},
204			expectedResolutions: []res{
205				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
206				{"gplBin.meta_lic", "apacheLib.meta_lic", "notice|restricted"},
207			},
208		},
209		{
210			name:      "gplonfprestricted",
211			condition: ImpliesRestricted,
212			roots:     []string{"gplBin.meta_lic"},
213			edges: []annotated{
214				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
215			},
216			expectedResolutions: []res{
217				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
218				{"gplBin.meta_lic", "apacheLib.meta_lic", "restricted"},
219			},
220		},
221		{
222			name:      "gplcontainernotice",
223			condition: ImpliesNotice,
224			roots:     []string{"gplContainer.meta_lic"},
225			edges: []annotated{
226				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
227			},
228			expectedResolutions: []res{
229				{"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"},
230				{"gplContainer.meta_lic", "apacheLib.meta_lic", "notice|restricted"},
231				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice|restricted"},
232			},
233		},
234		{
235			name:      "gplcontainerrestricted",
236			condition: ImpliesRestricted,
237			roots:     []string{"gplContainer.meta_lic"},
238			edges: []annotated{
239				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
240			},
241			expectedResolutions: []res{
242				{"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"},
243				{"gplContainer.meta_lic", "apacheLib.meta_lic", "restricted"},
244				{"apacheLib.meta_lic", "apacheLib.meta_lic", "restricted"},
245			},
246		},
247		{
248			name:      "gploncontainernotice",
249			condition: ImpliesNotice,
250			roots:     []string{"apacheContainer.meta_lic"},
251			edges: []annotated{
252				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
253				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
254			},
255			expectedResolutions: []res{
256				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice|restricted"},
257				{"apacheContainer.meta_lic", "apacheLib.meta_lic", "notice"},
258				{"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
259				{"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"},
260				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
261			},
262		},
263		{
264			name:      "gploncontainerrestricted",
265			condition: ImpliesRestricted,
266			roots:     []string{"apacheContainer.meta_lic"},
267			edges: []annotated{
268				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
269				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
270			},
271			expectedResolutions: []res{
272				{"apacheContainer.meta_lic", "apacheContainer.meta_lic", "restricted"},
273				{"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"},
274				{"gplLib.meta_lic", "gplLib.meta_lic", "restricted"},
275			},
276		},
277		{
278			name:      "gplonbinnotice",
279			condition: ImpliesNotice,
280			roots:     []string{"apacheBin.meta_lic"},
281			edges: []annotated{
282				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
283				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
284			},
285			expectedResolutions: []res{
286				{"apacheBin.meta_lic", "apacheBin.meta_lic", "notice|restricted"},
287				{"apacheBin.meta_lic", "apacheLib.meta_lic", "notice|restricted"},
288				{"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
289			},
290		},
291		{
292			name:      "gplonbinrestricted",
293			condition: ImpliesRestricted,
294			roots:     []string{"apacheBin.meta_lic"},
295			edges: []annotated{
296				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
297				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
298			},
299			expectedResolutions: []res{
300				{"apacheBin.meta_lic", "apacheBin.meta_lic", "restricted"},
301				{"apacheBin.meta_lic", "apacheLib.meta_lic", "restricted"},
302				{"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"},
303			},
304		},
305		{
306			name:      "gplonfpdynamicnotice",
307			condition: ImpliesNotice,
308			roots:     []string{"gplBin.meta_lic"},
309			edges: []annotated{
310				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
311			},
312			expectedResolutions: []res{
313				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
314			},
315		},
316		{
317			name:      "gplonfpdynamicrestricted",
318			condition: ImpliesRestricted,
319			roots:     []string{"gplBin.meta_lic"},
320			edges: []annotated{
321				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
322			},
323			expectedResolutions: []res{
324				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
325			},
326		},
327		{
328			name:      "gplonfpdynamicrestrictedshipped",
329			condition: ImpliesRestricted,
330			roots:     []string{"gplBin.meta_lic", "apacheLib.meta_lic"},
331			edges: []annotated{
332				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
333			},
334			expectedResolutions: []res{
335				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
336				{"gplBin.meta_lic", "apacheLib.meta_lic", "restricted"},
337				{"apacheLib.meta_lic", "apacheLib.meta_lic", "restricted"},
338			},
339		},
340		{
341			name:      "independentmodulereversenotice",
342			condition: ImpliesNotice,
343			roots:     []string{"gplWithClasspathException.meta_lic"},
344			edges: []annotated{
345				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
346			},
347			expectedResolutions: []res{
348				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "permissive"},
349			},
350		},
351		{
352			name:      "independentmodulereverserestricted",
353			condition: ImpliesRestricted,
354			roots:     []string{"gplWithClasspathException.meta_lic"},
355			edges: []annotated{
356				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
357			},
358			expectedResolutions: []res{},
359		},
360		{
361			name:      "independentmodulereverserestrictedshipped",
362			condition: ImpliesRestricted,
363			roots:     []string{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic"},
364			edges: []annotated{
365				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
366			},
367			expectedResolutions: []res{},
368		},
369		{
370			name:      "independentmodulereversestaticnotice",
371			condition: ImpliesNotice,
372			roots:     []string{"gplWithClasspathException.meta_lic"},
373			edges: []annotated{
374				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
375			},
376			expectedResolutions: []res{
377				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "permissive"},
378				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", "notice"},
379			},
380		},
381		{
382			name:      "independentmodulereversestaticrestricted",
383			condition: ImpliesRestricted,
384			roots:     []string{"gplWithClasspathException.meta_lic"},
385			edges: []annotated{
386				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
387			},
388			expectedResolutions: []res{},
389		},
390		{
391			name:      "dependentmodulereversenotice",
392			condition: ImpliesNotice,
393			roots:     []string{"gplWithClasspathException.meta_lic"},
394			edges: []annotated{
395				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
396			},
397			expectedResolutions: []res{
398				{"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "permissive"},
399			},
400		},
401		{
402			name:      "dependentmodulereverserestricted",
403			condition: ImpliesRestricted,
404			roots:     []string{"gplWithClasspathException.meta_lic"},
405			edges: []annotated{
406				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
407			},
408			expectedResolutions: []res{},
409		},
410		{
411			name:      "dependentmodulereverserestrictedshipped",
412			condition: ImpliesRestricted,
413			roots:     []string{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic"},
414			edges: []annotated{
415				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
416			},
417			expectedResolutions: []res{},
418		},
419		{
420			name:      "ponrnotice",
421			condition: ImpliesNotice,
422			roots:     []string{"proprietary.meta_lic"},
423			edges: []annotated{
424				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
425			},
426			expectedResolutions: []res{
427				{"proprietary.meta_lic", "proprietary.meta_lic", "restricted|proprietary"},
428				{"proprietary.meta_lic", "gplLib.meta_lic", "restricted"},
429			},
430		},
431		{
432			name:      "ponrrestricted",
433			condition: ImpliesRestricted,
434			roots:     []string{"proprietary.meta_lic"},
435			edges: []annotated{
436				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
437			},
438			expectedResolutions: []res{
439				{"proprietary.meta_lic", "gplLib.meta_lic", "restricted"},
440				{"proprietary.meta_lic", "proprietary.meta_lic", "restricted"},
441			},
442		},
443		{
444			name:      "ponrproprietary",
445			condition: ImpliesProprietary,
446			roots:     []string{"proprietary.meta_lic"},
447			edges: []annotated{
448				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
449			},
450			expectedResolutions: []res{
451				{"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"},
452			},
453		},
454		{
455			name:      "ronpnotice",
456			condition: ImpliesNotice,
457			roots:     []string{"gplBin.meta_lic"},
458			edges: []annotated{
459				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
460			},
461			expectedResolutions: []res{
462				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
463				{"gplBin.meta_lic", "proprietary.meta_lic", "restricted|proprietary"},
464			},
465		},
466		{
467			name:      "ronprestricted",
468			condition: ImpliesRestricted,
469			roots:     []string{"gplBin.meta_lic"},
470			edges: []annotated{
471				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
472			},
473			expectedResolutions: []res{
474				{"gplBin.meta_lic", "gplBin.meta_lic", "restricted"},
475				{"gplBin.meta_lic", "proprietary.meta_lic", "restricted"},
476			},
477		},
478		{
479			name:      "ronpproprietary",
480			condition: ImpliesProprietary,
481			roots:     []string{"gplBin.meta_lic"},
482			edges: []annotated{
483				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
484			},
485			expectedResolutions: []res{
486				{"gplBin.meta_lic", "proprietary.meta_lic", "proprietary"},
487			},
488		},
489		{
490			name:      "noticeonb_e_onotice",
491			condition: ImpliesNotice,
492			roots:     []string{"mitBin.meta_lic"},
493			edges: []annotated{
494				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
495			},
496			expectedResolutions: []res{
497				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
498				{"mitBin.meta_lic", "by_exception.meta_lic", "by_exception_only"},
499			},
500		},
501		{
502			name:      "noticeonb_e_orestricted",
503			condition: ImpliesRestricted,
504			roots:     []string{"mitBin.meta_lic"},
505			edges: []annotated{
506				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
507			},
508			expectedResolutions: []res{},
509		},
510		{
511			name:      "noticeonb_e_ob_e_o",
512			condition: ImpliesByExceptionOnly,
513			roots:     []string{"mitBin.meta_lic"},
514			edges: []annotated{
515				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
516			},
517			expectedResolutions: []res{
518				{"mitBin.meta_lic", "by_exception.meta_lic", "by_exception_only"},
519			},
520		},
521		{
522			name:      "b_e_oonnoticenotice",
523			condition: ImpliesNotice,
524			roots:     []string{"by_exception.meta_lic"},
525			edges: []annotated{
526				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
527			},
528			expectedResolutions: []res{
529				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
530				{"by_exception.meta_lic", "mitLib.meta_lic", "notice"},
531			},
532		},
533		{
534			name:      "b_e_oonnoticerestricted",
535			condition: ImpliesRestricted,
536			roots:     []string{"by_exception.meta_lic"},
537			edges: []annotated{
538				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
539			},
540			expectedResolutions: []res{},
541		},
542		{
543			name:      "b_e_oonnoticeb_e_o",
544			condition: ImpliesByExceptionOnly,
545			roots:     []string{"by_exception.meta_lic"},
546			edges: []annotated{
547				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
548			},
549			expectedResolutions: []res{
550				{"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"},
551			},
552		},
553		{
554			name:      "noticeonrecipnotice",
555			condition: ImpliesNotice,
556			roots:     []string{"mitBin.meta_lic"},
557			edges: []annotated{
558				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
559			},
560			expectedResolutions: []res{
561				{"mitBin.meta_lic", "mitBin.meta_lic", "notice"},
562				{"mitBin.meta_lic", "mplLib.meta_lic", "reciprocal"},
563			},
564		},
565		{
566			name:      "noticeonreciprecip",
567			condition: ImpliesReciprocal,
568			roots:     []string{"mitBin.meta_lic"},
569			edges: []annotated{
570				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
571			},
572			expectedResolutions: []res{
573				{"mitBin.meta_lic", "mplLib.meta_lic", "reciprocal"},
574			},
575		},
576		{
577			name:      "reciponnoticenotice",
578			condition: ImpliesNotice,
579			roots:     []string{"mplBin.meta_lic"},
580			edges: []annotated{
581				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
582			},
583			expectedResolutions: []res{
584				{"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"},
585				{"mplBin.meta_lic", "mitLib.meta_lic", "notice"},
586			},
587		},
588		{
589			name:      "reciponnoticerecip",
590			condition: ImpliesReciprocal,
591			roots:     []string{"mplBin.meta_lic"},
592			edges: []annotated{
593				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
594			},
595			expectedResolutions: []res{
596				{"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"},
597			},
598		},
599	}
600	for _, tt := range tests {
601		t.Run(tt.name, func(t *testing.T) {
602			stderr := &bytes.Buffer{}
603			lg, err := toGraph(stderr, tt.roots, tt.edges)
604			if err != nil {
605				t.Errorf("unexpected test data error: got %s, want no error", err)
606				return
607			}
608			expectedRs := toResolutionSet(lg, tt.expectedResolutions)
609			ResolveTopDownConditions(lg)
610			actualRs := WalkResolutionsForCondition(lg, tt.condition)
611			checkResolves(actualRs, expectedRs, t)
612		})
613	}
614}
615
616func TestWalkActionsForCondition(t *testing.T) {
617	tests := []struct {
618		name            string
619		condition       LicenseConditionSet
620		roots           []string
621		edges           []annotated
622		expectedActions []act
623	}{
624		{
625			name:      "firstparty",
626			condition: ImpliesNotice,
627			roots:     []string{"apacheBin.meta_lic"},
628			edges: []annotated{
629				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
630			},
631			expectedActions: []act{
632				{"apacheBin.meta_lic", "notice"},
633				{"apacheLib.meta_lic", "notice"},
634			},
635		},
636		{
637			name:      "notice",
638			condition: ImpliesNotice,
639			roots:     []string{"mitBin.meta_lic"},
640			edges: []annotated{
641				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
642			},
643			expectedActions: []act{
644				{"mitBin.meta_lic", "notice"},
645				{"mitLib.meta_lic", "notice"},
646			},
647		},
648		{
649			name:      "fponlgplnotice",
650			condition: ImpliesNotice,
651			roots:     []string{"apacheBin.meta_lic"},
652			edges: []annotated{
653				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
654			},
655			expectedActions: []act{
656				{"apacheBin.meta_lic", "notice"},
657				{"lgplLib.meta_lic", "restricted_if_statically_linked"},
658			},
659		},
660		{
661			name:      "fponlgpldynamicnotice",
662			condition: ImpliesNotice,
663			roots:     []string{"apacheBin.meta_lic"},
664			edges: []annotated{
665				{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
666			},
667			expectedActions: []act{
668				{"apacheBin.meta_lic", "notice"},
669			},
670		},
671		{
672			name:      "independentmodulenotice",
673			condition: ImpliesNotice,
674			roots:     []string{"apacheBin.meta_lic"},
675			edges: []annotated{
676				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
677			},
678			expectedActions: []act{
679				{"apacheBin.meta_lic", "notice"},
680			},
681		},
682		{
683			name:      "independentmodulerestricted",
684			condition: ImpliesRestricted,
685			roots:     []string{"apacheBin.meta_lic"},
686			edges: []annotated{
687				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
688			},
689			expectedActions: []act{},
690		},
691		{
692			name:      "independentmodulestaticnotice",
693			condition: ImpliesNotice,
694			roots:     []string{"apacheBin.meta_lic"},
695			edges: []annotated{
696				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
697			},
698			expectedActions: []act{
699				{"apacheBin.meta_lic", "notice"},
700				{"gplWithClasspathException.meta_lic", "permissive"},
701			},
702		},
703		{
704			name:      "independentmodulestaticrestricted",
705			condition: ImpliesRestricted,
706			roots:     []string{"apacheBin.meta_lic"},
707			edges: []annotated{
708				{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
709			},
710			expectedActions: []act{},
711		},
712		{
713			name:      "dependentmodulenotice",
714			condition: ImpliesNotice,
715			roots:     []string{"dependentModule.meta_lic"},
716			edges: []annotated{
717				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
718			},
719			expectedActions: []act{
720				{"dependentModule.meta_lic", "notice"},
721			},
722		},
723		{
724			name:      "dependentmodulerestricted",
725			condition: ImpliesRestricted,
726			roots:     []string{"dependentModule.meta_lic"},
727			edges: []annotated{
728				{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
729			},
730			expectedActions: []act{},
731		},
732		{
733			name:      "lgplonfpnotice",
734			condition: ImpliesNotice,
735			roots:     []string{"lgplBin.meta_lic"},
736			edges: []annotated{
737				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
738			},
739			expectedActions: []act{
740				{"lgplBin.meta_lic", "restricted_if_statically_linked"},
741				{"apacheLib.meta_lic", "notice|restricted_if_statically_linked"},
742			},
743		},
744		{
745			name:      "lgplonfprestricted",
746			condition: ImpliesRestricted,
747			roots:     []string{"lgplBin.meta_lic"},
748			edges: []annotated{
749				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
750			},
751			expectedActions: []act{
752				{"lgplBin.meta_lic", "restricted_if_statically_linked"},
753				{"apacheLib.meta_lic", "restricted_if_statically_linked"},
754			},
755		},
756		{
757			name:      "lgplonfpdynamicnotice",
758			condition: ImpliesNotice,
759			roots:     []string{"lgplBin.meta_lic"},
760			edges: []annotated{
761				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
762			},
763			expectedActions: []act{
764				{"lgplBin.meta_lic", "restricted_if_statically_linked"},
765			},
766		},
767		{
768			name:      "lgplonfpdynamicrestricted",
769			condition: ImpliesRestricted,
770			roots:     []string{"lgplBin.meta_lic"},
771			edges: []annotated{
772				{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
773			},
774			expectedActions: []act{
775				{"lgplBin.meta_lic", "restricted_if_statically_linked"},
776			},
777		},
778		{
779			name:      "gplonfpnotice",
780			condition: ImpliesNotice,
781			roots:     []string{"gplBin.meta_lic"},
782			edges: []annotated{
783				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
784			},
785			expectedActions: []act{
786				{"gplBin.meta_lic", "restricted"},
787				{"apacheLib.meta_lic", "notice|restricted"},
788			},
789		},
790		{
791			name:      "gplonfprestricted",
792			condition: ImpliesRestricted,
793			roots:     []string{"gplBin.meta_lic"},
794			edges: []annotated{
795				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
796			},
797			expectedActions: []act{
798				{"gplBin.meta_lic", "restricted"},
799				{"apacheLib.meta_lic", "restricted"},
800			},
801		},
802		{
803			name:      "gplcontainernotice",
804			condition: ImpliesNotice,
805			roots:     []string{"gplContainer.meta_lic"},
806			edges: []annotated{
807				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
808			},
809			expectedActions: []act{
810				{"gplContainer.meta_lic", "restricted"},
811				{"apacheLib.meta_lic", "notice|restricted"},
812			},
813		},
814		{
815			name:      "gplcontainerrestricted",
816			condition: ImpliesRestricted,
817			roots:     []string{"gplContainer.meta_lic"},
818			edges: []annotated{
819				{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
820			},
821			expectedActions: []act{
822				{"gplContainer.meta_lic", "restricted"},
823				{"apacheLib.meta_lic", "restricted"},
824			},
825		},
826		{
827			name:      "gploncontainernotice",
828			condition: ImpliesNotice,
829			roots:     []string{"apacheContainer.meta_lic"},
830			edges: []annotated{
831				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
832				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
833			},
834			expectedActions: []act{
835				{"apacheContainer.meta_lic", "notice|restricted"},
836				{"apacheLib.meta_lic", "notice"},
837				{"gplLib.meta_lic", "restricted"},
838			},
839		},
840		{
841			name:      "gploncontainerrestricted",
842			condition: ImpliesRestricted,
843			roots:     []string{"apacheContainer.meta_lic"},
844			edges: []annotated{
845				{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
846				{"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}},
847			},
848			expectedActions: []act{
849				{"apacheContainer.meta_lic", "restricted"},
850				{"gplLib.meta_lic", "restricted"},
851			},
852		},
853		{
854			name:      "gplonbinnotice",
855			condition: ImpliesNotice,
856			roots:     []string{"apacheBin.meta_lic"},
857			edges: []annotated{
858				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
859				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
860			},
861			expectedActions: []act{
862				{"apacheBin.meta_lic", "notice|restricted"},
863				{"apacheLib.meta_lic", "notice|restricted"},
864				{"gplLib.meta_lic", "restricted"},
865			},
866		},
867		{
868			name:      "gplonbinrestricted",
869			condition: ImpliesRestricted,
870			roots:     []string{"apacheBin.meta_lic"},
871			edges: []annotated{
872				{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
873				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
874			},
875			expectedActions: []act{
876				{"apacheBin.meta_lic", "restricted"},
877				{"apacheLib.meta_lic", "restricted"},
878				{"gplLib.meta_lic", "restricted"},
879			},
880		},
881		{
882			name:      "gplonfpdynamicnotice",
883			condition: ImpliesNotice,
884			roots:     []string{"gplBin.meta_lic"},
885			edges: []annotated{
886				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
887			},
888			expectedActions: []act{
889				{"gplBin.meta_lic", "restricted"},
890			},
891		},
892		{
893			name:      "gplonfpdynamicrestricted",
894			condition: ImpliesRestricted,
895			roots:     []string{"gplBin.meta_lic"},
896			edges: []annotated{
897				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
898			},
899			expectedActions: []act{
900				{"gplBin.meta_lic", "restricted"},
901			},
902		},
903		{
904			name:      "gplonfpdynamicrestrictedshipped",
905			condition: ImpliesRestricted,
906			roots:     []string{"gplBin.meta_lic", "apacheLib.meta_lic"},
907			edges: []annotated{
908				{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
909			},
910			expectedActions: []act{
911				{"gplBin.meta_lic", "restricted"},
912				{"apacheLib.meta_lic", "restricted"},
913			},
914		},
915		{
916			name:      "independentmodulereversenotice",
917			condition: ImpliesNotice,
918			roots:     []string{"gplWithClasspathException.meta_lic"},
919			edges: []annotated{
920				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
921			},
922			expectedActions: []act{
923				{"gplWithClasspathException.meta_lic", "permissive"},
924			},
925		},
926		{
927			name:      "independentmodulereverserestricted",
928			condition: ImpliesRestricted,
929			roots:     []string{"gplWithClasspathException.meta_lic"},
930			edges: []annotated{
931				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
932			},
933			expectedActions: []act{},
934		},
935		{
936			name:      "independentmodulereverserestrictedshipped",
937			condition: ImpliesRestricted,
938			roots:     []string{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic"},
939			edges: []annotated{
940				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
941			},
942			expectedActions: []act{},
943		},
944		{
945			name:      "independentmodulereversestaticnotice",
946			condition: ImpliesNotice,
947			roots:     []string{"gplWithClasspathException.meta_lic"},
948			edges: []annotated{
949				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
950			},
951			expectedActions: []act{
952				{"gplWithClasspathException.meta_lic", "permissive"},
953				{"apacheBin.meta_lic", "notice"},
954			},
955		},
956		{
957			name:      "independentmodulereversestaticrestricted",
958			condition: ImpliesRestricted,
959			roots:     []string{"gplWithClasspathException.meta_lic"},
960			edges: []annotated{
961				{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
962			},
963			expectedActions: []act{},
964		},
965		{
966			name:      "dependentmodulereversenotice",
967			condition: ImpliesNotice,
968			roots:     []string{"gplWithClasspathException.meta_lic"},
969			edges: []annotated{
970				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
971			},
972			expectedActions: []act{
973				{"gplWithClasspathException.meta_lic", "permissive"},
974			},
975		},
976		{
977			name:      "dependentmodulereverserestricted",
978			condition: ImpliesRestricted,
979			roots:     []string{"gplWithClasspathException.meta_lic"},
980			edges: []annotated{
981				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
982			},
983			expectedActions: []act{},
984		},
985		{
986			name:      "dependentmodulereverserestrictedshipped",
987			condition: ImpliesRestricted,
988			roots:     []string{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic"},
989			edges: []annotated{
990				{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
991			},
992			expectedActions: []act{},
993		},
994		{
995			name:      "ponrnotice",
996			condition: ImpliesNotice,
997			roots:     []string{"proprietary.meta_lic"},
998			edges: []annotated{
999				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
1000			},
1001			expectedActions: []act{
1002				{"proprietary.meta_lic", "restricted|proprietary"},
1003				{"gplLib.meta_lic", "restricted"},
1004			},
1005		},
1006		{
1007			name:      "ponrrestricted",
1008			condition: ImpliesRestricted,
1009			roots:     []string{"proprietary.meta_lic"},
1010			edges: []annotated{
1011				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
1012			},
1013			expectedActions: []act{
1014				{"gplLib.meta_lic", "restricted"},
1015				{"proprietary.meta_lic", "restricted"},
1016			},
1017		},
1018		{
1019			name:      "ponrproprietary",
1020			condition: ImpliesProprietary,
1021			roots:     []string{"proprietary.meta_lic"},
1022			edges: []annotated{
1023				{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
1024			},
1025			expectedActions: []act{
1026				{"proprietary.meta_lic", "proprietary"},
1027			},
1028		},
1029		{
1030			name:      "ronpnotice",
1031			condition: ImpliesNotice,
1032			roots:     []string{"gplBin.meta_lic"},
1033			edges: []annotated{
1034				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
1035			},
1036			expectedActions: []act{
1037				{"gplBin.meta_lic", "restricted"},
1038				{"proprietary.meta_lic", "restricted|proprietary"},
1039			},
1040		},
1041		{
1042			name:      "ronprestricted",
1043			condition: ImpliesRestricted,
1044			roots:     []string{"gplBin.meta_lic"},
1045			edges: []annotated{
1046				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
1047			},
1048			expectedActions: []act{
1049				{"gplBin.meta_lic", "restricted"},
1050				{"proprietary.meta_lic", "restricted"},
1051			},
1052		},
1053		{
1054			name:      "ronpproprietary",
1055			condition: ImpliesProprietary,
1056			roots:     []string{"gplBin.meta_lic"},
1057			edges: []annotated{
1058				{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
1059			},
1060			expectedActions: []act{
1061				{"proprietary.meta_lic", "proprietary"},
1062			},
1063		},
1064		{
1065			name:      "noticeonb_e_onotice",
1066			condition: ImpliesNotice,
1067			roots:     []string{"mitBin.meta_lic"},
1068			edges: []annotated{
1069				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
1070			},
1071			expectedActions: []act{
1072				{"mitBin.meta_lic", "notice"},
1073				{"by_exception.meta_lic", "by_exception_only"},
1074			},
1075		},
1076		{
1077			name:      "noticeonb_e_orestricted",
1078			condition: ImpliesRestricted,
1079			roots:     []string{"mitBin.meta_lic"},
1080			edges: []annotated{
1081				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
1082			},
1083			expectedActions: []act{},
1084		},
1085		{
1086			name:      "noticeonb_e_ob_e_o",
1087			condition: ImpliesByExceptionOnly,
1088			roots:     []string{"mitBin.meta_lic"},
1089			edges: []annotated{
1090				{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
1091			},
1092			expectedActions: []act{
1093				{"by_exception.meta_lic", "by_exception_only"},
1094			},
1095		},
1096		{
1097			name:      "b_e_oonnoticenotice",
1098			condition: ImpliesNotice,
1099			roots:     []string{"by_exception.meta_lic"},
1100			edges: []annotated{
1101				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
1102			},
1103			expectedActions: []act{
1104				{"by_exception.meta_lic", "by_exception_only"},
1105				{"mitLib.meta_lic", "notice"},
1106			},
1107		},
1108		{
1109			name:      "b_e_oonnoticerestricted",
1110			condition: ImpliesRestricted,
1111			roots:     []string{"by_exception.meta_lic"},
1112			edges: []annotated{
1113				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
1114			},
1115			expectedActions: []act{},
1116		},
1117		{
1118			name:      "b_e_oonnoticeb_e_o",
1119			condition: ImpliesByExceptionOnly,
1120			roots:     []string{"by_exception.meta_lic"},
1121			edges: []annotated{
1122				{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
1123			},
1124			expectedActions: []act{
1125				{"by_exception.meta_lic", "by_exception_only"},
1126			},
1127		},
1128		{
1129			name:      "noticeonrecipnotice",
1130			condition: ImpliesNotice,
1131			roots:     []string{"mitBin.meta_lic"},
1132			edges: []annotated{
1133				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
1134			},
1135			expectedActions: []act{
1136				{"mitBin.meta_lic", "notice"},
1137				{"mplLib.meta_lic", "reciprocal"},
1138			},
1139		},
1140		{
1141			name:      "noticeonreciprecip",
1142			condition: ImpliesReciprocal,
1143			roots:     []string{"mitBin.meta_lic"},
1144			edges: []annotated{
1145				{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
1146			},
1147			expectedActions: []act{
1148				{"mplLib.meta_lic", "reciprocal"},
1149			},
1150		},
1151		{
1152			name:      "reciponnoticenotice",
1153			condition: ImpliesNotice,
1154			roots:     []string{"mplBin.meta_lic"},
1155			edges: []annotated{
1156				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
1157			},
1158			expectedActions: []act{
1159				{"mplBin.meta_lic", "reciprocal"},
1160				{"mitLib.meta_lic", "notice"},
1161			},
1162		},
1163		{
1164			name:      "reciponnoticerecip",
1165			condition: ImpliesReciprocal,
1166			roots:     []string{"mplBin.meta_lic"},
1167			edges: []annotated{
1168				{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
1169			},
1170			expectedActions: []act{
1171				{"mplBin.meta_lic", "reciprocal"},
1172			},
1173		},
1174		{
1175			name:      "regress-walk-twice",
1176			condition: ImpliesShared,
1177			roots:     []string{"mitBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic"},
1178			edges: []annotated{
1179				{"apacheBin.meta_lic", "mitLib.meta_lic", []string{"dynamic"}},
1180				{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
1181				{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
1182				{"mitBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
1183			},
1184			expectedActions: []act{
1185				{"apacheBin.meta_lic", "restricted"},
1186				{"mitLib.meta_lic", "restricted|restricted_if_statically_linked"},
1187				{"gplLib.meta_lic", "restricted"},
1188				{"mitBin.meta_lic", "restricted_if_statically_linked"},
1189				{"lgplLib.meta_lic", "restricted_if_statically_linked"},
1190			},
1191		},
1192	}
1193	for _, tt := range tests {
1194		t.Run(tt.name, func(t *testing.T) {
1195			stderr := &bytes.Buffer{}
1196			lg, err := toGraph(stderr, tt.roots, tt.edges)
1197			if err != nil {
1198				t.Errorf("unexpected test data error: got %s, want no error", err)
1199				return
1200			}
1201			expectedAs := toActionSet(lg, tt.expectedActions)
1202			ResolveTopDownConditions(lg)
1203			actualAs := WalkActionsForCondition(lg, tt.condition)
1204			checkResolvesActions(lg, actualAs, expectedAs, t)
1205		})
1206	}
1207}
1208
1209func TestWalkTopDownBreadthFirst(t *testing.T) {
1210	tests := []struct {
1211		name           string
1212		roots          []string
1213		edges          []annotated
1214		expectedResult []string
1215	}{
1216		{
1217			name:  "bin/bin1",
1218			roots: []string{"bin/bin1.meta_lic"},
1219			expectedResult: []string{
1220				"testdata/notice/bin/bin1.meta_lic",
1221				"testdata/notice/lib/liba.so.meta_lic",
1222				"testdata/notice/lib/libc.a.meta_lic",
1223			},
1224		},
1225		{
1226			name:  "bin/bin2",
1227			roots: []string{"bin/bin2.meta_lic"},
1228			expectedResult: []string{
1229				"testdata/notice/bin/bin2.meta_lic",
1230				"testdata/notice/lib/libb.so.meta_lic",
1231				"testdata/notice/lib/libd.so.meta_lic",
1232			},
1233		},
1234		{
1235			name:  "bin/bin3",
1236			roots: []string{"bin/bin3.meta_lic"},
1237			expectedResult: []string{
1238				"testdata/notice/bin/bin3.meta_lic",
1239			},
1240		},
1241		{
1242			name:  "lib/liba.so",
1243			roots: []string{"lib/liba.so.meta_lic"},
1244			expectedResult: []string{
1245				"testdata/notice/lib/liba.so.meta_lic",
1246			},
1247		},
1248		{
1249			name:  "lib/libb.so",
1250			roots: []string{"lib/libb.so.meta_lic"},
1251			expectedResult: []string{
1252				"testdata/notice/lib/libb.so.meta_lic",
1253			},
1254		},
1255		{
1256			name:  "lib/libc.so",
1257			roots: []string{"lib/libc.a.meta_lic"},
1258			expectedResult: []string{
1259				"testdata/notice/lib/libc.a.meta_lic",
1260			},
1261		},
1262		{
1263			name:  "lib/libd.so",
1264			roots: []string{"lib/libd.so.meta_lic"},
1265			expectedResult: []string{
1266				"testdata/notice/lib/libd.so.meta_lic",
1267			},
1268		},
1269		{
1270			name:  "highest.apex",
1271			roots: []string{"highest.apex.meta_lic"},
1272			expectedResult: []string{
1273				"testdata/notice/highest.apex.meta_lic",
1274				"testdata/notice/bin/bin1.meta_lic",
1275				"testdata/notice/bin/bin2.meta_lic",
1276				"testdata/notice/lib/liba.so.meta_lic",
1277				"testdata/notice/lib/libb.so.meta_lic",
1278				"testdata/notice/lib/liba.so.meta_lic",
1279				"testdata/notice/lib/libc.a.meta_lic",
1280				"testdata/notice/lib/libb.so.meta_lic",
1281				"testdata/notice/lib/libd.so.meta_lic",
1282			},
1283		},
1284		{
1285			name:  "container.zip",
1286			roots: []string{"container.zip.meta_lic"},
1287			expectedResult: []string{
1288				"testdata/notice/container.zip.meta_lic",
1289				"testdata/notice/bin/bin1.meta_lic",
1290				"testdata/notice/bin/bin2.meta_lic",
1291				"testdata/notice/lib/liba.so.meta_lic",
1292				"testdata/notice/lib/libb.so.meta_lic",
1293				"testdata/notice/lib/liba.so.meta_lic",
1294				"testdata/notice/lib/libc.a.meta_lic",
1295				"testdata/notice/lib/libb.so.meta_lic",
1296				"testdata/notice/lib/libd.so.meta_lic",
1297			},
1298		},
1299		{
1300			name:  "application",
1301			roots: []string{"application.meta_lic"},
1302			expectedResult: []string{
1303				"testdata/notice/application.meta_lic",
1304				"testdata/notice/bin/bin3.meta_lic",
1305				"testdata/notice/lib/liba.so.meta_lic",
1306				"testdata/notice/lib/libb.so.meta_lic",
1307			},
1308		},
1309		{
1310			name:  "bin/bin1&lib/liba",
1311			roots: []string{"bin/bin1.meta_lic","lib/liba.so.meta_lic"},
1312			expectedResult: []string{
1313				"testdata/notice/bin/bin1.meta_lic",
1314				"testdata/notice/lib/liba.so.meta_lic",
1315				"testdata/notice/lib/liba.so.meta_lic",
1316				"testdata/notice/lib/libc.a.meta_lic",
1317			},
1318		},
1319		{
1320			name:  "bin/bin2&lib/libd",
1321			roots: []string{"bin/bin2.meta_lic", "lib/libd.so.meta_lic"},
1322			expectedResult: []string{
1323				"testdata/notice/bin/bin2.meta_lic",
1324				"testdata/notice/lib/libd.so.meta_lic",
1325				"testdata/notice/lib/libb.so.meta_lic",
1326				"testdata/notice/lib/libd.so.meta_lic",
1327			},
1328		},
1329		{
1330			name:  "application&bin/bin3",
1331			roots: []string{"application.meta_lic", "bin/bin3.meta_lic"},
1332			expectedResult: []string{
1333				"testdata/notice/application.meta_lic",
1334				"testdata/notice/bin/bin3.meta_lic",
1335				"testdata/notice/bin/bin3.meta_lic",
1336				"testdata/notice/lib/liba.so.meta_lic",
1337				"testdata/notice/lib/libb.so.meta_lic",
1338			},
1339		},
1340		{
1341			name:  "highest.apex&container.zip",
1342			roots: []string{"highest.apex.meta_lic", "container.zip.meta_lic"},
1343			expectedResult: []string{
1344				"testdata/notice/highest.apex.meta_lic",
1345				"testdata/notice/container.zip.meta_lic",
1346				"testdata/notice/bin/bin1.meta_lic",
1347				"testdata/notice/bin/bin2.meta_lic",
1348				"testdata/notice/lib/liba.so.meta_lic",
1349				"testdata/notice/lib/libb.so.meta_lic",
1350				"testdata/notice/lib/liba.so.meta_lic",
1351				"testdata/notice/lib/libc.a.meta_lic",
1352				"testdata/notice/lib/libb.so.meta_lic",
1353				"testdata/notice/lib/libd.so.meta_lic",
1354				"testdata/notice/bin/bin1.meta_lic",
1355				"testdata/notice/bin/bin2.meta_lic",
1356				"testdata/notice/lib/liba.so.meta_lic",
1357				"testdata/notice/lib/libb.so.meta_lic",
1358				"testdata/notice/lib/liba.so.meta_lic",
1359				"testdata/notice/lib/libc.a.meta_lic",
1360				"testdata/notice/lib/libb.so.meta_lic",
1361				"testdata/notice/lib/libd.so.meta_lic",
1362			},
1363		},
1364	}
1365
1366	for _, tt := range tests {
1367		t.Run(tt.name, func(t *testing.T) {
1368			stderr := &bytes.Buffer{}
1369			actualOut := &bytes.Buffer{}
1370
1371			rootFiles := make([]string, 0, len(tt.roots))
1372			for _, r := range tt.roots {
1373				rootFiles = append(rootFiles, "testdata/notice/"+r)
1374			}
1375
1376			lg, err := ReadLicenseGraph(GetFS(""), stderr, rootFiles)
1377
1378			if err != nil {
1379				t.Errorf("unexpected test data error: got %s, want no error", err)
1380				return
1381			}
1382
1383			expectedRst := tt.expectedResult
1384
1385			WalkTopDownBreadthFirst(nil, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
1386				fmt.Fprintln(actualOut, tn.Name())
1387				return true
1388			})
1389
1390			actualRst := strings.Split(actualOut.String(), "\n")
1391
1392			if len(actualRst) > 0 {
1393				actualRst = actualRst[:len(actualRst)-1]
1394			}
1395
1396			t.Logf("actual nodes visited: %s", actualOut.String())
1397			t.Logf("expected nodes visited: %s", strings.Join(expectedRst, "\n"))
1398
1399			if len(actualRst) != len(expectedRst) {
1400				t.Errorf("WalkTopDownBreadthFirst: number of visited nodes is different: got %d, want %d", len(actualRst), len(expectedRst))
1401			}
1402
1403			for i := 0; i < len(actualRst) && i < len(expectedRst); i++ {
1404				if actualRst[i] != expectedRst[i] {
1405					t.Errorf("WalkTopDownBreadthFirst: lines differ at index %d: got %q, want %q", i, actualRst[i], expectedRst[i])
1406					break
1407				}
1408			}
1409
1410			if len(actualRst) < len(expectedRst) {
1411				t.Errorf("WalkTopDownBreadthFirst: extra lines at %d: got %q, want nothing", len(actualRst), expectedRst[len(actualRst)])
1412			}
1413
1414			if len(expectedRst) < len(actualRst) {
1415				t.Errorf("WalkTopDownBreadthFirst: missing lines at %d: got nothing, want %q", len(expectedRst), actualRst[len(expectedRst)])
1416			}
1417		})
1418	}
1419}
1420
1421func TestWalkTopDownBreadthFirstWithoutDuplicates(t *testing.T) {
1422	tests := []struct {
1423		name           string
1424		roots          []string
1425		edges          []annotated
1426		expectedResult []string
1427	}{
1428		{
1429			name:  "bin/bin1",
1430			roots: []string{"bin/bin1.meta_lic"},
1431			expectedResult: []string{
1432				"testdata/notice/bin/bin1.meta_lic",
1433				"testdata/notice/lib/liba.so.meta_lic",
1434				"testdata/notice/lib/libc.a.meta_lic",
1435			},
1436		},
1437		{
1438			name:  "bin/bin2",
1439			roots: []string{"bin/bin2.meta_lic"},
1440			expectedResult: []string{
1441				"testdata/notice/bin/bin2.meta_lic",
1442				"testdata/notice/lib/libb.so.meta_lic",
1443				"testdata/notice/lib/libd.so.meta_lic",
1444			},
1445		},
1446		{
1447			name:  "bin/bin3",
1448			roots: []string{"bin/bin3.meta_lic"},
1449			expectedResult: []string{
1450				"testdata/notice/bin/bin3.meta_lic",
1451			},
1452		},
1453		{
1454			name:  "lib/liba.so",
1455			roots: []string{"lib/liba.so.meta_lic"},
1456			expectedResult: []string{
1457				"testdata/notice/lib/liba.so.meta_lic",
1458			},
1459		},
1460		{
1461			name:  "lib/libb.so",
1462			roots: []string{"lib/libb.so.meta_lic"},
1463			expectedResult: []string{
1464				"testdata/notice/lib/libb.so.meta_lic",
1465			},
1466		},
1467		{
1468			name:  "lib/libc.so",
1469			roots: []string{"lib/libc.a.meta_lic"},
1470			expectedResult: []string{
1471				"testdata/notice/lib/libc.a.meta_lic",
1472			},
1473		},
1474		{
1475			name:  "lib/libd.so",
1476			roots: []string{"lib/libd.so.meta_lic"},
1477			expectedResult: []string{
1478				"testdata/notice/lib/libd.so.meta_lic",
1479			},
1480		},
1481		{
1482			name:  "highest.apex",
1483			roots: []string{"highest.apex.meta_lic"},
1484			expectedResult: []string{
1485				"testdata/notice/highest.apex.meta_lic",
1486				"testdata/notice/bin/bin1.meta_lic",
1487				"testdata/notice/bin/bin2.meta_lic",
1488				"testdata/notice/lib/liba.so.meta_lic",
1489				"testdata/notice/lib/libb.so.meta_lic",
1490				"testdata/notice/lib/libc.a.meta_lic",
1491				"testdata/notice/lib/libd.so.meta_lic",
1492			},
1493		},
1494		{
1495			name:  "container.zip",
1496			roots: []string{"container.zip.meta_lic"},
1497			expectedResult: []string{
1498				"testdata/notice/container.zip.meta_lic",
1499				"testdata/notice/bin/bin1.meta_lic",
1500				"testdata/notice/bin/bin2.meta_lic",
1501				"testdata/notice/lib/liba.so.meta_lic",
1502				"testdata/notice/lib/libb.so.meta_lic",
1503				"testdata/notice/lib/libc.a.meta_lic",
1504				"testdata/notice/lib/libd.so.meta_lic",
1505			},
1506		},
1507		{
1508			name:  "application",
1509			roots: []string{"application.meta_lic"},
1510			expectedResult: []string{
1511				"testdata/notice/application.meta_lic",
1512				"testdata/notice/bin/bin3.meta_lic",
1513				"testdata/notice/lib/liba.so.meta_lic",
1514				"testdata/notice/lib/libb.so.meta_lic",
1515			},
1516		},
1517		{
1518			name:  "bin/bin1&lib/liba",
1519			roots: []string{"bin/bin1.meta_lic", "lib/liba.so.meta_lic"},
1520			expectedResult: []string{
1521				"testdata/notice/bin/bin1.meta_lic",
1522				"testdata/notice/lib/liba.so.meta_lic",
1523				"testdata/notice/lib/libc.a.meta_lic",
1524			},
1525		},
1526		{
1527			name:  "bin/bin2&lib/libd",
1528			roots: []string{"bin/bin2.meta_lic", "lib/libd.so.meta_lic"},
1529			expectedResult: []string{
1530				"testdata/notice/bin/bin2.meta_lic",
1531				"testdata/notice/lib/libd.so.meta_lic",
1532				"testdata/notice/lib/libb.so.meta_lic",
1533			},
1534		},
1535		{
1536			name:  "application&bin/bin3",
1537			roots: []string{"application.meta_lic", "bin/bin3.meta_lic"},
1538			expectedResult: []string{
1539				"testdata/notice/application.meta_lic",
1540				"testdata/notice/bin/bin3.meta_lic",
1541				"testdata/notice/lib/liba.so.meta_lic",
1542				"testdata/notice/lib/libb.so.meta_lic",
1543			},
1544		},
1545		{
1546			name:  "highest.apex&container.zip",
1547			roots: []string{"highest.apex.meta_lic", "container.zip.meta_lic"},
1548			expectedResult: []string{
1549				"testdata/notice/highest.apex.meta_lic",
1550				"testdata/notice/container.zip.meta_lic",
1551				"testdata/notice/bin/bin1.meta_lic",
1552				"testdata/notice/bin/bin2.meta_lic",
1553				"testdata/notice/lib/liba.so.meta_lic",
1554				"testdata/notice/lib/libb.so.meta_lic",
1555				"testdata/notice/lib/libc.a.meta_lic",
1556				"testdata/notice/lib/libd.so.meta_lic",
1557			},
1558		},
1559	}
1560
1561	for _, tt := range tests {
1562		t.Run(tt.name, func(t *testing.T) {
1563			stderr := &bytes.Buffer{}
1564			actualOut := &bytes.Buffer{}
1565
1566			rootFiles := make([]string, 0, len(tt.roots))
1567			for _, r := range tt.roots {
1568				rootFiles = append(rootFiles, "testdata/notice/"+r)
1569			}
1570
1571			lg, err := ReadLicenseGraph(GetFS(""), stderr, rootFiles)
1572
1573			if err != nil {
1574				t.Errorf("unexpected test data error: got %s, want no error", err)
1575				return
1576			}
1577
1578			expectedRst := tt.expectedResult
1579
1580			//Keeping track of the visited nodes
1581			//Only add to actualOut if not visited
1582			visitedNodes := make(map[string]struct{})
1583			WalkTopDownBreadthFirst(nil, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
1584				if _, alreadyVisited := visitedNodes[tn.Name()]; alreadyVisited {
1585					return false
1586				}
1587				fmt.Fprintln(actualOut, tn.Name())
1588				visitedNodes[tn.Name()] = struct{}{}
1589				return true
1590			})
1591
1592			actualRst := strings.Split(actualOut.String(), "\n")
1593
1594			if len(actualRst) > 0 {
1595				actualRst = actualRst[:len(actualRst)-1]
1596			}
1597
1598			t.Logf("actual nodes visited: %s", actualOut.String())
1599			t.Logf("expected nodes visited: %s", strings.Join(expectedRst, "\n"))
1600
1601			if len(actualRst) != len(expectedRst) {
1602				t.Errorf("WalkTopDownBreadthFirst: number of visited nodes is different: got %d, want %d", len(actualRst), len(expectedRst))
1603			}
1604
1605			for i := 0; i < len(actualRst) && i < len(expectedRst); i++ {
1606				if actualRst[i] != expectedRst[i] {
1607					t.Errorf("WalkTopDownBreadthFirst: lines differ at index %d: got %q, want %q", i, actualRst[i], expectedRst[i])
1608					break
1609				}
1610			}
1611
1612			if len(actualRst) < len(expectedRst) {
1613				t.Errorf("WalkTopDownBreadthFirst: extra lines at %d: got %q, want nothing", len(actualRst), expectedRst[len(actualRst)])
1614			}
1615
1616			if len(expectedRst) < len(actualRst) {
1617				t.Errorf("WalkTopDownBreadthFirst: missing lines at %d: got nothing, want %q", len(expectedRst), actualRst[len(expectedRst)])
1618			}
1619		})
1620	}
1621}
1622