1package android
2
3import (
4	"testing"
5
6	"github.com/google/blueprint"
7)
8
9var licensesTests = []struct {
10	name                       string
11	fs                         MockFS
12	expectedErrors             []string
13	effectiveLicenses          map[string][]string
14	effectiveInheritedLicenses map[string][]string
15	effectivePackage           map[string]string
16	effectiveNotices           map[string][]string
17	effectiveKinds             map[string][]string
18	effectiveConditions        map[string][]string
19}{
20	{
21		name: "invalid module type without licenses property",
22		fs: map[string][]byte{
23			"top/Blueprints": []byte(`
24				mock_bad_module {
25					name: "libexample",
26				}`),
27		},
28		expectedErrors: []string{`module type "mock_bad_module" must have an applicable licenses property`},
29	},
30	{
31		name: "license must exist",
32		fs: map[string][]byte{
33			"top/Blueprints": []byte(`
34				mock_library {
35					name: "libexample",
36					licenses: ["notice"],
37				}`),
38		},
39		expectedErrors: []string{`"libexample" depends on undefined module "notice"`},
40	},
41	{
42		name: "all good",
43		fs: map[string][]byte{
44			"top/Blueprints": []byte(`
45				license_kind {
46					name: "notice",
47					conditions: ["shownotice"],
48				}
49
50				license {
51					name: "top_Apache2",
52					license_kinds: ["notice"],
53					package_name: "topDog",
54					license_text: ["LICENSE", "NOTICE"],
55				}
56
57				mock_library {
58					name: "libexample1",
59					licenses: ["top_Apache2"],
60				}`),
61			"top/nested/Blueprints": []byte(`
62				mock_library {
63					name: "libnested",
64					licenses: ["top_Apache2"],
65				}`),
66			"other/Blueprints": []byte(`
67				mock_library {
68					name: "libother",
69					licenses: ["top_Apache2"],
70				}`),
71		},
72		effectiveLicenses: map[string][]string{
73			"libexample1": []string{"top_Apache2"},
74			"libnested":   []string{"top_Apache2"},
75			"libother":    []string{"top_Apache2"},
76		},
77		effectiveKinds: map[string][]string{
78			"libexample1": []string{"notice"},
79			"libnested":   []string{"notice"},
80			"libother":    []string{"notice"},
81		},
82		effectivePackage: map[string]string{
83			"libexample1": "topDog",
84			"libnested":   "topDog",
85			"libother":    "topDog",
86		},
87		effectiveConditions: map[string][]string{
88			"libexample1": []string{"shownotice"},
89			"libnested":   []string{"shownotice"},
90			"libother":    []string{"shownotice"},
91		},
92		effectiveNotices: map[string][]string{
93			"libexample1": []string{"top/LICENSE", "top/NOTICE"},
94			"libnested":   []string{"top/LICENSE", "top/NOTICE"},
95			"libother":    []string{"top/LICENSE", "top/NOTICE"},
96		},
97	},
98
99	// Defaults propagation tests
100	{
101		// Check that licenses is the union of the defaults modules.
102		name: "defaults union, basic",
103		fs: map[string][]byte{
104			"top/Blueprints": []byte(`
105				license_kind {
106					name: "top_notice",
107					conditions: ["notice"],
108				}
109
110				license {
111					name: "top_other",
112					license_kinds: ["top_notice"],
113				}
114
115				mock_defaults {
116					name: "libexample_defaults",
117					licenses: ["top_other"],
118				}
119				mock_library {
120					name: "libexample",
121					licenses: ["nested_other"],
122					defaults: ["libexample_defaults"],
123				}
124				mock_library {
125					name: "libsamepackage",
126					deps: ["libexample"],
127				}`),
128			"top/nested/Blueprints": []byte(`
129				license_kind {
130					name: "nested_notice",
131					conditions: ["notice"],
132				}
133
134				license {
135					name: "nested_other",
136					license_kinds: ["nested_notice"],
137				}
138
139				mock_library {
140					name: "libnested",
141					deps: ["libexample"],
142				}`),
143			"other/Blueprints": []byte(`
144				mock_library {
145					name: "libother",
146					deps: ["libexample"],
147				}`),
148		},
149		effectiveLicenses: map[string][]string{
150			"libexample":     []string{"nested_other", "top_other"},
151			"libsamepackage": []string{},
152			"libnested":      []string{},
153			"libother":       []string{},
154		},
155		effectiveInheritedLicenses: map[string][]string{
156			"libexample":     []string{"nested_other", "top_other"},
157			"libsamepackage": []string{"nested_other", "top_other"},
158			"libnested":      []string{"nested_other", "top_other"},
159			"libother":       []string{"nested_other", "top_other"},
160		},
161		effectiveKinds: map[string][]string{
162			"libexample":     []string{"nested_notice", "top_notice"},
163			"libsamepackage": []string{},
164			"libnested":      []string{},
165			"libother":       []string{},
166		},
167		effectiveConditions: map[string][]string{
168			"libexample":     []string{"notice"},
169			"libsamepackage": []string{},
170			"libnested":      []string{},
171			"libother":       []string{},
172		},
173	},
174	{
175		name: "defaults union, multiple defaults",
176		fs: map[string][]byte{
177			"top/Blueprints": []byte(`
178				license {
179					name: "top",
180				}
181				mock_defaults {
182					name: "libexample_defaults_1",
183					licenses: ["other"],
184				}
185				mock_defaults {
186					name: "libexample_defaults_2",
187					licenses: ["top_nested"],
188				}
189				mock_library {
190					name: "libexample",
191					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
192				}
193				mock_library {
194					name: "libsamepackage",
195					deps: ["libexample"],
196				}`),
197			"top/nested/Blueprints": []byte(`
198				license {
199					name: "top_nested",
200					license_text: ["LICENSE.txt"],
201				}
202				mock_library {
203					name: "libnested",
204					deps: ["libexample"],
205				}`),
206			"other/Blueprints": []byte(`
207				license {
208					name: "other",
209				}
210				mock_library {
211					name: "libother",
212					deps: ["libexample"],
213				}`),
214			"outsider/Blueprints": []byte(`
215				mock_library {
216					name: "liboutsider",
217					deps: ["libexample"],
218				}`),
219		},
220		effectiveLicenses: map[string][]string{
221			"libexample":     []string{"other", "top_nested"},
222			"libsamepackage": []string{},
223			"libnested":      []string{},
224			"libother":       []string{},
225			"liboutsider":    []string{},
226		},
227		effectiveInheritedLicenses: map[string][]string{
228			"libexample":     []string{"other", "top_nested"},
229			"libsamepackage": []string{"other", "top_nested"},
230			"libnested":      []string{"other", "top_nested"},
231			"libother":       []string{"other", "top_nested"},
232			"liboutsider":    []string{"other", "top_nested"},
233		},
234		effectiveKinds: map[string][]string{
235			"libexample":     []string{},
236			"libsamepackage": []string{},
237			"libnested":      []string{},
238			"libother":       []string{},
239			"liboutsider":    []string{},
240		},
241		effectiveNotices: map[string][]string{
242			"libexample":     []string{"top/nested/LICENSE.txt"},
243			"libsamepackage": []string{},
244			"libnested":      []string{},
245			"libother":       []string{},
246			"liboutsider":    []string{},
247		},
248	},
249
250	// Defaults module's defaults_licenses tests
251	{
252		name: "defaults_licenses invalid",
253		fs: map[string][]byte{
254			"top/Blueprints": []byte(`
255				mock_defaults {
256					name: "top_defaults",
257					licenses: ["notice"],
258				}`),
259		},
260		expectedErrors: []string{`"top_defaults" depends on undefined module "notice"`},
261	},
262	{
263		name: "defaults_licenses overrides package default",
264		fs: map[string][]byte{
265			"top/Blueprints": []byte(`
266				package {
267					default_applicable_licenses: ["by_exception_only"],
268				}
269				license {
270					name: "by_exception_only",
271				}
272				license {
273					name: "notice",
274				}
275				mock_defaults {
276					name: "top_defaults",
277					licenses: ["notice"],
278				}
279				mock_library {
280					name: "libexample",
281				}
282				mock_library {
283					name: "libdefaults",
284					defaults: ["top_defaults"],
285				}`),
286		},
287		effectiveLicenses: map[string][]string{
288			"libexample":  []string{"by_exception_only"},
289			"libdefaults": []string{"notice"},
290		},
291		effectiveInheritedLicenses: map[string][]string{
292			"libexample":  []string{"by_exception_only"},
293			"libdefaults": []string{"notice"},
294		},
295	},
296
297	// Package default_applicable_licenses tests
298	{
299		name: "package default_applicable_licenses must exist",
300		fs: map[string][]byte{
301			"top/Blueprints": []byte(`
302				package {
303					default_applicable_licenses: ["notice"],
304				}`),
305		},
306		expectedErrors: []string{`"//top" depends on undefined module "notice"`},
307	},
308	{
309		// This test relies on the default licenses being legacy_public.
310		name: "package default_applicable_licenses property used when no licenses specified",
311		fs: map[string][]byte{
312			"top/Blueprints": []byte(`
313				package {
314					default_applicable_licenses: ["top_notice"],
315				}
316
317				license {
318					name: "top_notice",
319				}
320				mock_library {
321					name: "libexample",
322				}`),
323			"outsider/Blueprints": []byte(`
324				mock_library {
325					name: "liboutsider",
326					deps: ["libexample"],
327				}`),
328		},
329		effectiveLicenses: map[string][]string{
330			"libexample":  []string{"top_notice"},
331			"liboutsider": []string{},
332		},
333		effectiveInheritedLicenses: map[string][]string{
334			"libexample":  []string{"top_notice"},
335			"liboutsider": []string{"top_notice"},
336		},
337	},
338	{
339		name: "package default_applicable_licenses not inherited to subpackages",
340		fs: map[string][]byte{
341			"top/Blueprints": []byte(`
342				package {
343					default_applicable_licenses: ["top_notice"],
344				}
345				license {
346					name: "top_notice",
347				}
348				mock_library {
349					name: "libexample",
350				}`),
351			"top/nested/Blueprints": []byte(`
352				package {
353					default_applicable_licenses: ["outsider"],
354				}
355
356				mock_library {
357					name: "libnested",
358				}`),
359			"top/other/Blueprints": []byte(`
360				mock_library {
361					name: "libother",
362				}`),
363			"outsider/Blueprints": []byte(`
364				license {
365					name: "outsider",
366				}
367				mock_library {
368					name: "liboutsider",
369					deps: ["libexample", "libother", "libnested"],
370				}`),
371		},
372		effectiveLicenses: map[string][]string{
373			"libexample":  []string{"top_notice"},
374			"libnested":   []string{"outsider"},
375			"libother":    []string{},
376			"liboutsider": []string{},
377		},
378		effectiveInheritedLicenses: map[string][]string{
379			"libexample":  []string{"top_notice"},
380			"libnested":   []string{"outsider"},
381			"libother":    []string{},
382			"liboutsider": []string{"top_notice", "outsider"},
383		},
384	},
385	{
386		name: "verify that prebuilt dependencies are included",
387		fs: map[string][]byte{
388			"prebuilts/Blueprints": []byte(`
389				license {
390					name: "prebuilt"
391				}
392				prebuilt {
393					name: "module",
394					licenses: ["prebuilt"],
395				}`),
396			"top/sources/source_file": nil,
397			"top/sources/Blueprints": []byte(`
398				license {
399					name: "top_sources"
400				}
401				source {
402					name: "module",
403					licenses: ["top_sources"],
404				}`),
405			"top/other/source_file": nil,
406			"top/other/Blueprints": []byte(`
407				source {
408					name: "other",
409					deps: [":module"],
410				}`),
411		},
412		effectiveLicenses: map[string][]string{
413			"other": []string{},
414		},
415		effectiveInheritedLicenses: map[string][]string{
416			"other": []string{"prebuilt", "top_sources"},
417		},
418	},
419	{
420		name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)",
421		fs: map[string][]byte{
422			"prebuilts/Blueprints": []byte(`
423				license {
424					name: "prebuilt"
425				}
426				prebuilt {
427					name: "module",
428					licenses: ["prebuilt"],
429					prefer: true,
430				}`),
431			"top/sources/source_file": nil,
432			"top/sources/Blueprints": []byte(`
433				license {
434					name: "top_sources"
435				}
436				source {
437					name: "module",
438					licenses: ["top_sources"],
439				}`),
440			"top/other/source_file": nil,
441			"top/other/Blueprints": []byte(`
442				source {
443					name: "other",
444					deps: [":module"],
445				}`),
446		},
447		effectiveLicenses: map[string][]string{
448			"other": []string{},
449		},
450		effectiveInheritedLicenses: map[string][]string{
451			"module": []string{"prebuilt", "top_sources"},
452			"other":  []string{"prebuilt", "top_sources"},
453		},
454	},
455}
456
457func TestLicenses(t *testing.T) {
458	for _, test := range licensesTests {
459		t.Run(test.name, func(t *testing.T) {
460			// Customize the common license text fixture factory.
461			result := GroupFixturePreparers(
462				prepareForLicenseTest,
463				FixtureRegisterWithContext(func(ctx RegistrationContext) {
464					ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule)
465					ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule)
466					ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory)
467				}),
468				test.fs.AddToFixture(),
469			).
470				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
471				RunTest(t)
472
473			if test.effectiveLicenses != nil {
474				checkEffectiveLicenses(t, result, test.effectiveLicenses)
475			}
476
477			if test.effectivePackage != nil {
478				checkEffectivePackage(t, result, test.effectivePackage)
479			}
480
481			if test.effectiveNotices != nil {
482				checkEffectiveNotices(t, result, test.effectiveNotices)
483			}
484
485			if test.effectiveKinds != nil {
486				checkEffectiveKinds(t, result, test.effectiveKinds)
487			}
488
489			if test.effectiveConditions != nil {
490				checkEffectiveConditions(t, result, test.effectiveConditions)
491			}
492
493			if test.effectiveInheritedLicenses != nil {
494				checkEffectiveInheritedLicenses(t, result, test.effectiveInheritedLicenses)
495			}
496		})
497	}
498}
499
500func checkEffectiveLicenses(t *testing.T, result *TestResult, effectiveLicenses map[string][]string) {
501	actualLicenses := make(map[string][]string)
502	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
503		if _, ok := m.(*licenseModule); ok {
504			return
505		}
506		if _, ok := m.(*licenseKindModule); ok {
507			return
508		}
509		if _, ok := m.(*packageModule); ok {
510			return
511		}
512		module, ok := m.(Module)
513		if !ok {
514			t.Errorf("%q not a module", m.Name())
515			return
516		}
517		base := module.base()
518		if base == nil {
519			return
520		}
521		actualLicenses[m.Name()] = base.commonProperties.Effective_licenses
522	})
523
524	for moduleName, expectedLicenses := range effectiveLicenses {
525		licenses, ok := actualLicenses[moduleName]
526		if !ok {
527			licenses = []string{}
528		}
529		if !compareUnorderedStringArrays(expectedLicenses, licenses) {
530			t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses)
531		}
532	}
533}
534
535func checkEffectiveInheritedLicenses(t *testing.T, result *TestResult, effectiveInheritedLicenses map[string][]string) {
536	actualLicenses := make(map[string][]string)
537	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
538		if _, ok := m.(*licenseModule); ok {
539			return
540		}
541		if _, ok := m.(*licenseKindModule); ok {
542			return
543		}
544		if _, ok := m.(*packageModule); ok {
545			return
546		}
547		module, ok := m.(Module)
548		if !ok {
549			t.Errorf("%q not a module", m.Name())
550			return
551		}
552		base := module.base()
553		if base == nil {
554			return
555		}
556		inherited := make(map[string]bool)
557		for _, l := range base.commonProperties.Effective_licenses {
558			inherited[l] = true
559		}
560		result.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) {
561			if _, ok := c.(*licenseModule); ok {
562				return
563			}
564			if _, ok := c.(*licenseKindModule); ok {
565				return
566			}
567			if _, ok := c.(*packageModule); ok {
568				return
569			}
570			cmodule, ok := c.(Module)
571			if !ok {
572				t.Errorf("%q not a module", c.Name())
573				return
574			}
575			cbase := cmodule.base()
576			if cbase == nil {
577				return
578			}
579			for _, l := range cbase.commonProperties.Effective_licenses {
580				inherited[l] = true
581			}
582		})
583		actualLicenses[m.Name()] = []string{}
584		for l := range inherited {
585			actualLicenses[m.Name()] = append(actualLicenses[m.Name()], l)
586		}
587	})
588
589	for moduleName, expectedInheritedLicenses := range effectiveInheritedLicenses {
590		licenses, ok := actualLicenses[moduleName]
591		if !ok {
592			licenses = []string{}
593		}
594		if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) {
595			t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses)
596		}
597	}
598}
599
600func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) {
601	actualPackage := make(map[string]string)
602	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
603		if _, ok := m.(*licenseModule); ok {
604			return
605		}
606		if _, ok := m.(*licenseKindModule); ok {
607			return
608		}
609		if _, ok := m.(*packageModule); ok {
610			return
611		}
612		module, ok := m.(Module)
613		if !ok {
614			t.Errorf("%q not a module", m.Name())
615			return
616		}
617		base := module.base()
618		if base == nil {
619			return
620		}
621
622		if base.commonProperties.Effective_package_name == nil {
623			actualPackage[m.Name()] = ""
624		} else {
625			actualPackage[m.Name()] = *base.commonProperties.Effective_package_name
626		}
627	})
628
629	for moduleName, expectedPackage := range effectivePackage {
630		packageName, ok := actualPackage[moduleName]
631		if !ok {
632			packageName = ""
633		}
634		if expectedPackage != packageName {
635			t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName)
636		}
637	}
638}
639
640func checkEffectiveNotices(t *testing.T, result *TestResult, effectiveNotices map[string][]string) {
641	actualNotices := make(map[string][]string)
642	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
643		if _, ok := m.(*licenseModule); ok {
644			return
645		}
646		if _, ok := m.(*licenseKindModule); ok {
647			return
648		}
649		if _, ok := m.(*packageModule); ok {
650			return
651		}
652		module, ok := m.(Module)
653		if !ok {
654			t.Errorf("%q not a module", m.Name())
655			return
656		}
657		base := module.base()
658		if base == nil {
659			return
660		}
661		actualNotices[m.Name()] = base.commonProperties.Effective_license_text.Strings()
662	})
663
664	for moduleName, expectedNotices := range effectiveNotices {
665		notices, ok := actualNotices[moduleName]
666		if !ok {
667			notices = []string{}
668		}
669		if !compareUnorderedStringArrays(expectedNotices, notices) {
670			t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices)
671		}
672	}
673}
674
675func checkEffectiveKinds(t *testing.T, result *TestResult, effectiveKinds map[string][]string) {
676	actualKinds := make(map[string][]string)
677	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
678		if _, ok := m.(*licenseModule); ok {
679			return
680		}
681		if _, ok := m.(*licenseKindModule); ok {
682			return
683		}
684		if _, ok := m.(*packageModule); ok {
685			return
686		}
687		module, ok := m.(Module)
688		if !ok {
689			t.Errorf("%q not a module", m.Name())
690			return
691		}
692		base := module.base()
693		if base == nil {
694			return
695		}
696		actualKinds[m.Name()] = base.commonProperties.Effective_license_kinds
697	})
698
699	for moduleName, expectedKinds := range effectiveKinds {
700		kinds, ok := actualKinds[moduleName]
701		if !ok {
702			kinds = []string{}
703		}
704		if !compareUnorderedStringArrays(expectedKinds, kinds) {
705			t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds)
706		}
707	}
708}
709
710func checkEffectiveConditions(t *testing.T, result *TestResult, effectiveConditions map[string][]string) {
711	actualConditions := make(map[string][]string)
712	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
713		if _, ok := m.(*licenseModule); ok {
714			return
715		}
716		if _, ok := m.(*licenseKindModule); ok {
717			return
718		}
719		if _, ok := m.(*packageModule); ok {
720			return
721		}
722		module, ok := m.(Module)
723		if !ok {
724			t.Errorf("%q not a module", m.Name())
725			return
726		}
727		base := module.base()
728		if base == nil {
729			return
730		}
731		actualConditions[m.Name()] = base.commonProperties.Effective_license_conditions
732	})
733
734	for moduleName, expectedConditions := range effectiveConditions {
735		conditions, ok := actualConditions[moduleName]
736		if !ok {
737			conditions = []string{}
738		}
739		if !compareUnorderedStringArrays(expectedConditions, conditions) {
740			t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions)
741		}
742	}
743}
744
745func compareUnorderedStringArrays(expected, actual []string) bool {
746	if len(expected) != len(actual) {
747		return false
748	}
749	s := make(map[string]int)
750	for _, v := range expected {
751		s[v] += 1
752	}
753	for _, v := range actual {
754		c, ok := s[v]
755		if !ok {
756			return false
757		}
758		if c < 1 {
759			return false
760		}
761		s[v] -= 1
762	}
763	return true
764}
765
766type mockLicensesBadProperties struct {
767	Visibility []string
768}
769
770type mockLicensesBadModule struct {
771	ModuleBase
772	DefaultableModuleBase
773	properties mockLicensesBadProperties
774}
775
776func newMockLicensesBadModule() Module {
777	m := &mockLicensesBadModule{}
778
779	base := m.base()
780	m.AddProperties(&base.nameProperties, &m.properties)
781
782	base.generalProperties = m.GetProperties()
783	base.customizableProperties = m.GetProperties()
784
785	// The default_visibility property needs to be checked and parsed by the visibility module during
786	// its checking and parsing phases so make it the primary visibility property.
787	setPrimaryVisibilityProperty(m, "visibility", &m.properties.Visibility)
788
789	initAndroidModuleBase(m)
790	InitDefaultableModule(m)
791
792	return m
793}
794
795func (m *mockLicensesBadModule) GenerateAndroidBuildActions(ModuleContext) {
796}
797
798type mockLicensesLibraryProperties struct {
799	Deps []string
800}
801
802type mockLicensesLibraryModule struct {
803	ModuleBase
804	DefaultableModuleBase
805	properties mockLicensesLibraryProperties
806}
807
808func newMockLicensesLibraryModule() Module {
809	m := &mockLicensesLibraryModule{}
810	m.AddProperties(&m.properties)
811	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
812	InitDefaultableModule(m)
813	return m
814}
815
816type dependencyLicensesTag struct {
817	blueprint.BaseDependencyTag
818	name string
819}
820
821func (j *mockLicensesLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
822	ctx.AddVariationDependencies(nil, dependencyLicensesTag{name: "mockdeps"}, j.properties.Deps...)
823}
824
825func (p *mockLicensesLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
826}
827
828type mockLicensesDefaults struct {
829	ModuleBase
830	DefaultsModuleBase
831}
832
833func defaultsLicensesFactory() Module {
834	m := &mockLicensesDefaults{}
835	InitDefaultsModule(m)
836	return m
837}
838