1package android
2
3import (
4	"reflect"
5	"testing"
6
7	"github.com/google/blueprint"
8)
9
10var visibilityTests = []struct {
11	name                string
12	fs                  MockFS
13	expectedErrors      []string
14	effectiveVisibility map[qualifiedModuleName][]string
15}{
16	{
17		name: "invalid visibility: empty list",
18		fs: MockFS{
19			"top/Blueprints": []byte(`
20				mock_library {
21					name: "libexample",
22					visibility: [],
23				}`),
24		},
25		expectedErrors: []string{`visibility: must contain at least one visibility rule`},
26	},
27	{
28		name: "invalid visibility: empty rule",
29		fs: MockFS{
30			"top/Blueprints": []byte(`
31				mock_library {
32					name: "libexample",
33					visibility: [""],
34				}`),
35		},
36		expectedErrors: []string{`visibility: invalid visibility pattern ""`},
37	},
38	{
39		name: "invalid visibility: unqualified",
40		fs: MockFS{
41			"top/Blueprints": []byte(`
42				mock_library {
43					name: "libexample",
44					visibility: ["target"],
45				}`),
46		},
47		expectedErrors: []string{`visibility: invalid visibility pattern "target"`},
48	},
49	{
50		name: "invalid visibility: empty namespace",
51		fs: MockFS{
52			"top/Blueprints": []byte(`
53				mock_library {
54					name: "libexample",
55					visibility: ["//"],
56				}`),
57		},
58		expectedErrors: []string{`visibility: invalid visibility pattern "//"`},
59	},
60	{
61		name: "invalid visibility: empty module",
62		fs: MockFS{
63			"top/Blueprints": []byte(`
64				mock_library {
65					name: "libexample",
66					visibility: [":"],
67				}`),
68		},
69		expectedErrors: []string{`visibility: invalid visibility pattern ":"`},
70	},
71	{
72		name: "invalid visibility: empty namespace and module",
73		fs: MockFS{
74			"top/Blueprints": []byte(`
75				mock_library {
76					name: "libexample",
77					visibility: ["//:"],
78				}`),
79		},
80		expectedErrors: []string{`visibility: invalid visibility pattern "//:"`},
81	},
82	{
83		name: "//visibility:unknown",
84		fs: MockFS{
85			"top/Blueprints": []byte(`
86				mock_library {
87					name: "libexample",
88					visibility: ["//visibility:unknown"],
89				}`),
90		},
91		expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
92	},
93	{
94		name: "//visibility:xxx mixed",
95		fs: MockFS{
96			"top/Blueprints": []byte(`
97				mock_library {
98					name: "libexample",
99					visibility: ["//visibility:public", "//namespace"],
100				}
101
102				mock_library {
103					name: "libother",
104					visibility: ["//visibility:private", "//namespace"],
105				}`),
106		},
107		expectedErrors: []string{
108			`module "libother": visibility: cannot mix "//visibility:private"` +
109				` with any other visibility rules`,
110			`module "libexample": visibility: cannot mix "//visibility:public"` +
111				` with any other visibility rules`,
112		},
113	},
114	{
115		name: "//visibility:legacy_public",
116		fs: MockFS{
117			"top/Blueprints": []byte(`
118				mock_library {
119					name: "libexample",
120					visibility: ["//visibility:legacy_public"],
121				}`),
122		},
123		expectedErrors: []string{
124			`module "libexample": visibility: //visibility:legacy_public must` +
125				` not be used`,
126		},
127	},
128	{
129		// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
130		// the current directory, a nested directory and a directory in a separate tree.
131		name: "//visibility:public",
132		fs: MockFS{
133			"top/Blueprints": []byte(`
134				mock_library {
135					name: "libexample",
136					visibility: ["//visibility:public"],
137				}
138
139				mock_library {
140					name: "libsamepackage",
141					deps: ["libexample"],
142				}`),
143			"top/nested/Blueprints": []byte(`
144				mock_library {
145					name: "libnested",
146					deps: ["libexample"],
147				}`),
148			"other/Blueprints": []byte(`
149				mock_library {
150					name: "libother",
151					deps: ["libexample"],
152				}`),
153		},
154	},
155	{
156		// Verify that //visibility:private allows the module to be referenced from the current
157		// directory only.
158		name: "//visibility:private",
159		fs: MockFS{
160			"top/Blueprints": []byte(`
161				mock_library {
162					name: "libexample",
163					visibility: ["//visibility:private"],
164				}
165
166				mock_library {
167					name: "libsamepackage",
168					deps: ["libexample"],
169				}`),
170			"top/nested/Blueprints": []byte(`
171				mock_library {
172					name: "libnested",
173					deps: ["libexample"],
174				}`),
175			"other/Blueprints": []byte(`
176				mock_library {
177					name: "libother",
178					deps: ["libexample"],
179				}`),
180		},
181		expectedErrors: []string{
182			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
183				` visible to this module`,
184			`module "libother" variant "android_common": depends on //top:libexample which is not` +
185				` visible to this module`,
186		},
187	},
188	{
189		// Verify that :__pkg__ allows the module to be referenced from the current directory only.
190		name: ":__pkg__",
191		fs: MockFS{
192			"top/Blueprints": []byte(`
193				mock_library {
194					name: "libexample",
195					visibility: [":__pkg__"],
196				}
197
198				mock_library {
199					name: "libsamepackage",
200					deps: ["libexample"],
201				}`),
202			"top/nested/Blueprints": []byte(`
203				mock_library {
204					name: "libnested",
205					deps: ["libexample"],
206				}`),
207			"other/Blueprints": []byte(`
208				mock_library {
209					name: "libother",
210					deps: ["libexample"],
211				}`),
212		},
213		expectedErrors: []string{
214			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
215				` visible to this module`,
216			`module "libother" variant "android_common": depends on //top:libexample which is not` +
217				` visible to this module`,
218		},
219	},
220	{
221		// Verify that //top/nested allows the module to be referenced from the current directory and
222		// the top/nested directory only, not a subdirectory of top/nested and not peak directory.
223		name: "//top/nested",
224		fs: MockFS{
225			"top/Blueprints": []byte(`
226				mock_library {
227					name: "libexample",
228					visibility: ["//top/nested"],
229				}
230
231				mock_library {
232					name: "libsamepackage",
233					deps: ["libexample"],
234				}`),
235			"top/nested/Blueprints": []byte(`
236				mock_library {
237					name: "libnested",
238					deps: ["libexample"],
239				}`),
240			"top/nested/again/Blueprints": []byte(`
241				mock_library {
242					name: "libnestedagain",
243					deps: ["libexample"],
244				}`),
245			"peak/Blueprints": []byte(`
246				mock_library {
247					name: "libother",
248					deps: ["libexample"],
249				}`),
250		},
251		expectedErrors: []string{
252			`module "libother" variant "android_common": depends on //top:libexample which is not` +
253				` visible to this module`,
254			`module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
255				` visible to this module`,
256		},
257	},
258	{
259		// Verify that :__subpackages__ allows the module to be referenced from the current directory
260		// and sub directories but nowhere else.
261		name: ":__subpackages__",
262		fs: MockFS{
263			"top/Blueprints": []byte(`
264				mock_library {
265					name: "libexample",
266					visibility: [":__subpackages__"],
267				}
268
269				mock_library {
270					name: "libsamepackage",
271					deps: ["libexample"],
272				}`),
273			"top/nested/Blueprints": []byte(`
274				mock_library {
275					name: "libnested",
276					deps: ["libexample"],
277				}`),
278			"peak/other/Blueprints": []byte(`
279				mock_library {
280					name: "libother",
281					deps: ["libexample"],
282				}`),
283		},
284		expectedErrors: []string{
285			`module "libother" variant "android_common": depends on //top:libexample which is not` +
286				` visible to this module`,
287		},
288	},
289	{
290		// Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
291		// directory and sub directories but nowhere else.
292		name: "//top/nested:__subpackages__",
293		fs: MockFS{
294			"top/Blueprints": []byte(`
295				mock_library {
296					name: "libexample",
297					visibility: ["//top/nested:__subpackages__", "//other"],
298				}
299
300				mock_library {
301					name: "libsamepackage",
302					deps: ["libexample"],
303				}`),
304			"top/nested/Blueprints": []byte(`
305				mock_library {
306					name: "libnested",
307					deps: ["libexample"],
308				}`),
309			"top/other/Blueprints": []byte(`
310				mock_library {
311					name: "libother",
312					deps: ["libexample"],
313				}`),
314		},
315		expectedErrors: []string{
316			`module "libother" variant "android_common": depends on //top:libexample which is not` +
317				` visible to this module`,
318		},
319	},
320	{
321		// Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
322		// the current directory, top/nested and peak and all its subpackages.
323		name: `["//top/nested", "//peak:__subpackages__"]`,
324		fs: MockFS{
325			"top/Blueprints": []byte(`
326				mock_library {
327					name: "libexample",
328					visibility: ["//top/nested", "//peak:__subpackages__"],
329				}
330
331				mock_library {
332					name: "libsamepackage",
333					deps: ["libexample"],
334				}`),
335			"top/nested/Blueprints": []byte(`
336				mock_library {
337					name: "libnested",
338					deps: ["libexample"],
339				}`),
340			"peak/other/Blueprints": []byte(`
341				mock_library {
342					name: "libother",
343					deps: ["libexample"],
344				}`),
345		},
346	},
347	{
348		// Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
349		name: `//vendor`,
350		fs: MockFS{
351			"top/Blueprints": []byte(`
352				mock_library {
353					name: "libexample",
354					visibility: ["//vendor:__subpackages__"],
355				}
356
357				mock_library {
358					name: "libsamepackage",
359					visibility: ["//vendor/apps/AcmeSettings"],
360				}`),
361			"vendor/Blueprints": []byte(`
362				mock_library {
363					name: "libvendorexample",
364					deps: ["libexample"],
365					visibility: ["//vendor/nested"],
366				}`),
367			"vendor/nested/Blueprints": []byte(`
368				mock_library {
369					name: "libvendornested",
370					deps: ["libexample", "libvendorexample"],
371				}`),
372		},
373		expectedErrors: []string{
374			`module "libsamepackage": visibility: "//vendor/apps/AcmeSettings"` +
375				` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
376				` targets within //vendor, they can only use //vendor:__subpackages__.`,
377		},
378	},
379
380	// Defaults propagation tests
381	{
382		// Check that visibility is the union of the defaults modules.
383		name: "defaults union, basic",
384		fs: MockFS{
385			"top/Blueprints": []byte(`
386				mock_defaults {
387					name: "libexample_defaults",
388					visibility: ["//other"],
389				}
390				mock_library {
391					name: "libexample",
392					visibility: ["//top/nested"],
393					defaults: ["libexample_defaults"],
394				}
395				mock_library {
396					name: "libsamepackage",
397					deps: ["libexample"],
398				}`),
399			"top/nested/Blueprints": []byte(`
400				mock_library {
401					name: "libnested",
402					deps: ["libexample"],
403				}`),
404			"other/Blueprints": []byte(`
405				mock_library {
406					name: "libother",
407					deps: ["libexample"],
408				}`),
409			"outsider/Blueprints": []byte(`
410				mock_library {
411					name: "liboutsider",
412					deps: ["libexample"],
413				}`),
414		},
415		expectedErrors: []string{
416			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
417				` visible to this module`,
418		},
419	},
420	{
421		name: "defaults union, multiple defaults",
422		fs: MockFS{
423			"top/Blueprints": []byte(`
424				mock_defaults {
425					name: "libexample_defaults_1",
426					visibility: ["//other"],
427				}
428				mock_defaults {
429					name: "libexample_defaults_2",
430					visibility: ["//top/nested"],
431				}
432				mock_library {
433					name: "libexample",
434					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
435				}
436				mock_library {
437					name: "libsamepackage",
438					deps: ["libexample"],
439				}`),
440			"top/nested/Blueprints": []byte(`
441				mock_library {
442					name: "libnested",
443					deps: ["libexample"],
444				}`),
445			"other/Blueprints": []byte(`
446				mock_library {
447					name: "libother",
448					deps: ["libexample"],
449				}`),
450			"outsider/Blueprints": []byte(`
451				mock_library {
452					name: "liboutsider",
453					deps: ["libexample"],
454				}`),
455		},
456		expectedErrors: []string{
457			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
458				` visible to this module`,
459		},
460	},
461	{
462		name: "//visibility:public mixed with other in defaults",
463		fs: MockFS{
464			"top/Blueprints": []byte(`
465				mock_defaults {
466					name: "libexample_defaults",
467					visibility: ["//visibility:public", "//namespace"],
468				}
469				mock_library {
470					name: "libexample",
471					defaults: ["libexample_defaults"],
472				}`),
473		},
474		expectedErrors: []string{
475			`module "libexample_defaults": visibility: cannot mix "//visibility:public"` +
476				` with any other visibility rules`,
477		},
478	},
479	{
480		name: "//visibility:public overriding defaults",
481		fs: MockFS{
482			"top/Blueprints": []byte(`
483				mock_defaults {
484					name: "libexample_defaults",
485					visibility: ["//namespace"],
486				}
487				mock_library {
488					name: "libexample",
489					visibility: ["//visibility:public"],
490					defaults: ["libexample_defaults"],
491				}`),
492			"outsider/Blueprints": []byte(`
493				mock_library {
494					name: "liboutsider",
495					deps: ["libexample"],
496				}`),
497		},
498		effectiveVisibility: map[qualifiedModuleName][]string{
499			qualifiedModuleName{pkg: "top", name: "libexample"}: {"//visibility:public"},
500		},
501	},
502	{
503		name: "//visibility:public mixed with other from different defaults 1",
504		fs: MockFS{
505			"top/Blueprints": []byte(`
506				mock_defaults {
507					name: "libexample_defaults_1",
508					visibility: ["//namespace"],
509				}
510				mock_defaults {
511					name: "libexample_defaults_2",
512					visibility: ["//visibility:public"],
513				}
514				mock_library {
515					name: "libexample",
516					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
517				}`),
518			"outsider/Blueprints": []byte(`
519				mock_library {
520					name: "liboutsider",
521					deps: ["libexample"],
522				}`),
523		},
524	},
525	{
526		name: "//visibility:public mixed with other from different defaults 2",
527		fs: MockFS{
528			"top/Blueprints": []byte(`
529				mock_defaults {
530					name: "libexample_defaults_1",
531					visibility: ["//visibility:public"],
532				}
533				mock_defaults {
534					name: "libexample_defaults_2",
535					visibility: ["//namespace"],
536				}
537				mock_library {
538					name: "libexample",
539					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
540				}`),
541			"outsider/Blueprints": []byte(`
542				mock_library {
543					name: "liboutsider",
544					deps: ["libexample"],
545				}`),
546		},
547	},
548	{
549		name: "//visibility:private in defaults",
550		fs: MockFS{
551			"top/Blueprints": []byte(`
552				mock_defaults {
553					name: "libexample_defaults",
554					visibility: ["//visibility:private"],
555				}
556				mock_library {
557					name: "libexample",
558					defaults: ["libexample_defaults"],
559				}
560				mock_library {
561					name: "libsamepackage",
562					deps: ["libexample"],
563				}`),
564			"top/nested/Blueprints": []byte(`
565				mock_library {
566					name: "libnested",
567					deps: ["libexample"],
568				}`),
569			"other/Blueprints": []byte(`
570				mock_library {
571					name: "libother",
572					deps: ["libexample"],
573				}`),
574		},
575		expectedErrors: []string{
576			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
577				` visible to this module`,
578			`module "libother" variant "android_common": depends on //top:libexample which is not` +
579				` visible to this module`,
580		},
581	},
582	{
583		name: "//visibility:private mixed with other in defaults",
584		fs: MockFS{
585			"top/Blueprints": []byte(`
586				mock_defaults {
587					name: "libexample_defaults",
588					visibility: ["//visibility:private", "//namespace"],
589				}
590				mock_library {
591					name: "libexample",
592					defaults: ["libexample_defaults"],
593				}`),
594		},
595		expectedErrors: []string{
596			`module "libexample_defaults": visibility: cannot mix "//visibility:private"` +
597				` with any other visibility rules`,
598		},
599	},
600	{
601		name: "//visibility:private overriding defaults",
602		fs: MockFS{
603			"top/Blueprints": []byte(`
604				mock_defaults {
605					name: "libexample_defaults",
606					visibility: ["//namespace"],
607				}
608				mock_library {
609					name: "libexample",
610					visibility: ["//visibility:private"],
611					defaults: ["libexample_defaults"],
612				}`),
613		},
614		expectedErrors: []string{
615			`module "libexample": visibility: cannot mix "//visibility:private"` +
616				` with any other visibility rules`,
617		},
618	},
619	{
620		name: "//visibility:private in defaults overridden",
621		fs: MockFS{
622			"top/Blueprints": []byte(`
623				mock_defaults {
624					name: "libexample_defaults",
625					visibility: ["//visibility:private"],
626				}
627				mock_library {
628					name: "libexample",
629					visibility: ["//namespace"],
630					defaults: ["libexample_defaults"],
631				}`),
632		},
633		expectedErrors: []string{
634			`module "libexample": visibility: cannot mix "//visibility:private"` +
635				` with any other visibility rules`,
636		},
637	},
638	{
639		name: "//visibility:private override //visibility:public",
640		fs: MockFS{
641			"top/Blueprints": []byte(`
642				mock_defaults {
643					name: "libexample_defaults",
644					visibility: ["//visibility:public"],
645				}
646				mock_library {
647					name: "libexample",
648					visibility: ["//visibility:private"],
649					defaults: ["libexample_defaults"],
650				}`),
651		},
652		expectedErrors: []string{
653			`module "libexample": visibility: cannot mix "//visibility:private" with any other visibility rules`,
654		},
655	},
656	{
657		name: "//visibility:public override //visibility:private",
658		fs: MockFS{
659			"top/Blueprints": []byte(`
660				mock_defaults {
661					name: "libexample_defaults",
662					visibility: ["//visibility:private"],
663				}
664				mock_library {
665					name: "libexample",
666					visibility: ["//visibility:public"],
667					defaults: ["libexample_defaults"],
668				}`),
669		},
670		expectedErrors: []string{
671			`module "libexample": visibility: cannot mix "//visibility:private" with any other visibility rules`,
672		},
673	},
674	{
675		name: "//visibility:override must be first in the list",
676		fs: MockFS{
677			"top/Blueprints": []byte(`
678				mock_library {
679					name: "libexample",
680					visibility: ["//other", "//visibility:override", "//namespace"],
681				}`),
682		},
683		expectedErrors: []string{
684			`module "libexample": visibility: "//visibility:override" may only be used at the start of the visibility rules`,
685		},
686	},
687	{
688		name: "//visibility:override discards //visibility:private",
689		fs: MockFS{
690			"top/Blueprints": []byte(`
691				mock_defaults {
692					name: "libexample_defaults",
693					visibility: ["//visibility:private"],
694				}
695				mock_library {
696					name: "libexample",
697					// Make this visibility to //other but not //visibility:private
698					visibility: ["//visibility:override", "//other"],
699					defaults: ["libexample_defaults"],
700				}`),
701			"other/Blueprints": []byte(`
702				mock_library {
703					name: "libother",
704					deps: ["libexample"],
705				}`),
706		},
707	},
708	{
709		name: "//visibility:override discards //visibility:public",
710		fs: MockFS{
711			"top/Blueprints": []byte(`
712				mock_defaults {
713					name: "libexample_defaults",
714					visibility: ["//visibility:public"],
715				}
716				mock_library {
717					name: "libexample",
718					// Make this visibility to //other but not //visibility:public
719					visibility: ["//visibility:override", "//other"],
720					defaults: ["libexample_defaults"],
721				}`),
722			"other/Blueprints": []byte(`
723				mock_library {
724					name: "libother",
725					deps: ["libexample"],
726				}`),
727			"namespace/Blueprints": []byte(`
728				mock_library {
729					name: "libnamespace",
730					deps: ["libexample"],
731				}`),
732		},
733		expectedErrors: []string{
734			`module "libnamespace" variant "android_common": depends on //top:libexample which is not visible to this module\nYou may need to add "//namespace" to its visibility`,
735		},
736	},
737	{
738		name: "//visibility:override discards defaults supplied rules",
739		fs: MockFS{
740			"top/Blueprints": []byte(`
741				mock_defaults {
742					name: "libexample_defaults",
743					visibility: ["//namespace"],
744				}
745				mock_library {
746					name: "libexample",
747					// Make this visibility to //other but not //namespace
748					visibility: ["//visibility:override", "//other"],
749					defaults: ["libexample_defaults"],
750				}`),
751			"other/Blueprints": []byte(`
752				mock_library {
753					name: "libother",
754					deps: ["libexample"],
755				}`),
756			"namespace/Blueprints": []byte(`
757				mock_library {
758					name: "libnamespace",
759					deps: ["libexample"],
760				}`),
761		},
762		expectedErrors: []string{
763			`module "libnamespace" variant "android_common": depends on //top:libexample which is not visible to this module\nYou may need to add "//namespace" to its visibility`,
764		},
765	},
766	{
767		name: "//visibility:override can override //visibility:public with //visibility:private",
768		fs: MockFS{
769			"top/Blueprints": []byte(`
770				mock_defaults {
771					name: "libexample_defaults",
772					visibility: ["//visibility:public"],
773				}
774				mock_library {
775					name: "libexample",
776					visibility: ["//visibility:override", "//visibility:private"],
777					defaults: ["libexample_defaults"],
778				}`),
779			"namespace/Blueprints": []byte(`
780				mock_library {
781					name: "libnamespace",
782					deps: ["libexample"],
783				}`),
784		},
785		expectedErrors: []string{
786			`module "libnamespace" variant "android_common": depends on //top:libexample which is not visible to this module`,
787		},
788	},
789	{
790		name: "//visibility:override can override //visibility:private with //visibility:public",
791		fs: MockFS{
792			"top/Blueprints": []byte(`
793				mock_defaults {
794					name: "libexample_defaults",
795					visibility: ["//visibility:private"],
796				}
797				mock_library {
798					name: "libexample",
799					visibility: ["//visibility:override", "//visibility:public"],
800					defaults: ["libexample_defaults"],
801				}`),
802			"namespace/Blueprints": []byte(`
803				mock_library {
804					name: "libnamespace",
805					deps: ["libexample"],
806				}`),
807		},
808	},
809	{
810		name: "//visibility:private mixed with itself",
811		fs: MockFS{
812			"top/Blueprints": []byte(`
813				mock_defaults {
814					name: "libexample_defaults_1",
815					visibility: ["//visibility:private"],
816				}
817				mock_defaults {
818					name: "libexample_defaults_2",
819					visibility: ["//visibility:private"],
820				}
821				mock_library {
822					name: "libexample",
823					visibility: ["//visibility:private"],
824					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
825				}`),
826			"outsider/Blueprints": []byte(`
827				mock_library {
828					name: "liboutsider",
829					deps: ["libexample"],
830				}`),
831		},
832		expectedErrors: []string{
833			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
834				` visible to this module`,
835		},
836	},
837
838	// Defaults module's defaults_visibility tests
839	{
840		name: "defaults_visibility invalid",
841		fs: MockFS{
842			"top/Blueprints": []byte(`
843				mock_defaults {
844					name: "top_defaults",
845					defaults_visibility: ["//visibility:invalid"],
846				}`),
847		},
848		expectedErrors: []string{
849			`defaults_visibility: unrecognized visibility rule "//visibility:invalid"`,
850		},
851	},
852	{
853		name: "defaults_visibility overrides package default",
854		fs: MockFS{
855			"top/Blueprints": []byte(`
856				package {
857					default_visibility: ["//visibility:private"],
858				}
859				mock_defaults {
860					name: "top_defaults",
861					defaults_visibility: ["//visibility:public"],
862				}`),
863			"outsider/Blueprints": []byte(`
864				mock_library {
865					name: "liboutsider",
866					defaults: ["top_defaults"],
867				}`),
868		},
869	},
870
871	// Package default_visibility tests
872	{
873		name: "package default_visibility property is checked",
874		fs: MockFS{
875			"top/Blueprints": []byte(`
876				package {
877					default_visibility: ["//visibility:invalid"],
878				}`),
879		},
880		expectedErrors: []string{`default_visibility: unrecognized visibility rule "//visibility:invalid"`},
881	},
882	{
883		// This test relies on the default visibility being legacy_public.
884		name: "package default_visibility property used when no visibility specified",
885		fs: MockFS{
886			"top/Blueprints": []byte(`
887				package {
888					default_visibility: ["//visibility:private"],
889				}
890
891				mock_library {
892					name: "libexample",
893				}`),
894			"outsider/Blueprints": []byte(`
895				mock_library {
896					name: "liboutsider",
897					deps: ["libexample"],
898				}`),
899		},
900		expectedErrors: []string{
901			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
902				` visible to this module`,
903		},
904	},
905	{
906		name: "package default_visibility public does not override visibility private",
907		fs: MockFS{
908			"top/Blueprints": []byte(`
909				package {
910					default_visibility: ["//visibility:public"],
911				}
912
913				mock_library {
914					name: "libexample",
915					visibility: ["//visibility:private"],
916				}`),
917			"outsider/Blueprints": []byte(`
918				mock_library {
919					name: "liboutsider",
920					deps: ["libexample"],
921				}`),
922		},
923		expectedErrors: []string{
924			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
925				` visible to this module`,
926		},
927	},
928	{
929		name: "package default_visibility private does not override visibility public",
930		fs: MockFS{
931			"top/Blueprints": []byte(`
932				package {
933					default_visibility: ["//visibility:private"],
934				}
935
936				mock_library {
937					name: "libexample",
938					visibility: ["//visibility:public"],
939				}`),
940			"outsider/Blueprints": []byte(`
941				mock_library {
942					name: "liboutsider",
943					deps: ["libexample"],
944				}`),
945		},
946	},
947	{
948		name: "package default_visibility :__subpackages__",
949		fs: MockFS{
950			"top/Blueprints": []byte(`
951				package {
952					default_visibility: [":__subpackages__"],
953				}
954
955				mock_library {
956					name: "libexample",
957				}`),
958			"top/nested/Blueprints": []byte(`
959				mock_library {
960					name: "libnested",
961					deps: ["libexample"],
962				}`),
963			"outsider/Blueprints": []byte(`
964				mock_library {
965					name: "liboutsider",
966					deps: ["libexample"],
967				}`),
968		},
969		expectedErrors: []string{
970			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
971				` visible to this module`,
972		},
973	},
974	{
975		name: "package default_visibility inherited to subpackages",
976		fs: MockFS{
977			"top/Blueprints": []byte(`
978				package {
979					default_visibility: ["//outsider"],
980				}
981
982				mock_library {
983					name: "libexample",
984          visibility: [":__subpackages__"],
985				}`),
986			"top/nested/Blueprints": []byte(`
987				mock_library {
988					name: "libnested",
989					deps: ["libexample"],
990				}`),
991			"outsider/Blueprints": []byte(`
992				mock_library {
993					name: "liboutsider",
994					deps: ["libexample", "libnested"],
995				}`),
996		},
997		expectedErrors: []string{
998			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
999				` visible to this module`,
1000		},
1001	},
1002	{
1003		name: "package default_visibility inherited to subpackages",
1004		fs: MockFS{
1005			"top/Blueprints": []byte(`
1006				package {
1007					default_visibility: ["//visibility:private"],
1008				}`),
1009			"top/nested/Blueprints": []byte(`
1010				package {
1011					default_visibility: ["//outsider"],
1012				}
1013
1014				mock_library {
1015					name: "libnested",
1016				}`),
1017			"top/other/Blueprints": []byte(`
1018				mock_library {
1019					name: "libother",
1020				}`),
1021			"outsider/Blueprints": []byte(`
1022				mock_library {
1023					name: "liboutsider",
1024					deps: ["libother", "libnested"],
1025				}`),
1026		},
1027		expectedErrors: []string{
1028			`module "liboutsider" variant "android_common": depends on //top/other:libother which is` +
1029				` not visible to this module`,
1030		},
1031	},
1032	{
1033		name: "verify that prebuilt dependencies are ignored for visibility reasons (not preferred)",
1034		fs: MockFS{
1035			"prebuilts/Blueprints": []byte(`
1036				prebuilt {
1037					name: "module",
1038					visibility: ["//top/other"],
1039				}`),
1040			"top/sources/source_file": nil,
1041			"top/sources/Blueprints": []byte(`
1042				source {
1043					name: "module",
1044					visibility: ["//top/other"],
1045				}`),
1046			"top/other/source_file": nil,
1047			"top/other/Blueprints": []byte(`
1048				source {
1049					name: "other",
1050					deps: [":module"],
1051				}`),
1052		},
1053	},
1054	{
1055		name: "verify that prebuilt dependencies are ignored for visibility reasons (preferred)",
1056		fs: MockFS{
1057			"prebuilts/Blueprints": []byte(`
1058				prebuilt {
1059					name: "module",
1060					visibility: ["//top/other"],
1061					prefer: true,
1062				}`),
1063			"top/sources/source_file": nil,
1064			"top/sources/Blueprints": []byte(`
1065				source {
1066					name: "module",
1067					visibility: ["//top/other"],
1068				}`),
1069			"top/other/source_file": nil,
1070			"top/other/Blueprints": []byte(`
1071				source {
1072					name: "other",
1073					deps: [":module"],
1074				}`),
1075		},
1076	},
1077	{
1078		name: "ensure visibility properties are checked for correctness",
1079		fs: MockFS{
1080			"top/Blueprints": []byte(`
1081				mock_parent {
1082					name: "parent",
1083					visibility: ["//top/nested"],
1084					child: {
1085						name: "libchild",
1086						visibility: ["top/other"],
1087					},
1088				}`),
1089		},
1090		expectedErrors: []string{
1091			`module "parent": child.visibility: invalid visibility pattern "top/other"`,
1092		},
1093	},
1094	{
1095		name: "invalid visibility added to child detected during gather phase",
1096		fs: MockFS{
1097			"top/Blueprints": []byte(`
1098				mock_parent {
1099					name: "parent",
1100					visibility: ["//top/nested"],
1101					child: {
1102						name: "libchild",
1103						invalid_visibility: ["top/other"],
1104					},
1105				}`),
1106		},
1107		expectedErrors: []string{
1108			// That this error is reported against the child not the parent shows it was
1109			// not being detected in the parent which is correct as invalid_visibility is
1110			// purposely not added to the list of visibility properties to check, and was
1111			// in fact detected in the child in the gather phase. Contrast this error message
1112			// with the preceding one.
1113			`module "libchild" \(created by module "parent"\): visibility: invalid visibility pattern "top/other"`,
1114		},
1115	},
1116	{
1117		name: "automatic visibility inheritance enabled",
1118		fs: MockFS{
1119			"top/Blueprints": []byte(`
1120				mock_parent {
1121					name: "parent",
1122					visibility: ["//top/nested"],
1123					child: {
1124						name: "libchild",
1125						visibility: ["//top/other"],
1126					},
1127				}`),
1128			"top/nested/Blueprints": []byte(`
1129				mock_library {
1130					name: "libnested",
1131					deps: ["libchild"],
1132				}`),
1133			"top/other/Blueprints": []byte(`
1134				mock_library {
1135					name: "libother",
1136					deps: ["libchild"],
1137				}`),
1138		},
1139	},
1140}
1141
1142func TestVisibility(t *testing.T) {
1143	for _, test := range visibilityTests {
1144		t.Run(test.name, func(t *testing.T) {
1145			result := GroupFixturePreparers(
1146				// General preparers in alphabetical order as test infrastructure will enforce correct
1147				// registration order.
1148				PrepareForTestWithArchMutator,
1149				PrepareForTestWithDefaults,
1150				PrepareForTestWithOverrides,
1151				PrepareForTestWithPackageModule,
1152				PrepareForTestWithPrebuilts,
1153				PrepareForTestWithVisibility,
1154
1155				// Additional test specific preparers.
1156				FixtureRegisterWithContext(func(ctx RegistrationContext) {
1157					ctx.RegisterModuleType("mock_library", newMockLibraryModule)
1158					ctx.RegisterModuleType("mock_parent", newMockParentFactory)
1159					ctx.RegisterModuleType("mock_defaults", defaultsFactory)
1160				}),
1161				prepareForTestWithFakePrebuiltModules,
1162				// Add additional files to the mock filesystem
1163				test.fs.AddToFixture(),
1164			).
1165				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
1166				RunTest(t)
1167
1168			if test.effectiveVisibility != nil {
1169				checkEffectiveVisibility(t, result, test.effectiveVisibility)
1170			}
1171		})
1172	}
1173}
1174
1175func checkEffectiveVisibility(t *testing.T, result *TestResult, effectiveVisibility map[qualifiedModuleName][]string) {
1176	for moduleName, expectedRules := range effectiveVisibility {
1177		rule := effectiveVisibilityRules(result.Config, moduleName)
1178		stringRules := rule.Strings()
1179		AssertDeepEquals(t, "effective rules mismatch", expectedRules, stringRules)
1180	}
1181}
1182
1183type mockLibraryProperties struct {
1184	Deps []string
1185}
1186
1187type mockLibraryModule struct {
1188	ModuleBase
1189	DefaultableModuleBase
1190	properties mockLibraryProperties
1191}
1192
1193func newMockLibraryModule() Module {
1194	m := &mockLibraryModule{}
1195	m.AddProperties(&m.properties)
1196	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
1197	InitDefaultableModule(m)
1198	return m
1199}
1200
1201type dependencyTag struct {
1202	blueprint.BaseDependencyTag
1203	name string
1204}
1205
1206func (j *mockLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
1207	ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
1208}
1209
1210func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
1211}
1212
1213type mockDefaults struct {
1214	ModuleBase
1215	DefaultsModuleBase
1216}
1217
1218func defaultsFactory() Module {
1219	m := &mockDefaults{}
1220	InitDefaultsModule(m)
1221	return m
1222}
1223
1224type mockParentProperties struct {
1225	Child struct {
1226		Name *string
1227
1228		// Visibility to pass to the child module.
1229		Visibility []string
1230
1231		// Purposely not validated visibility to pass to the child.
1232		Invalid_visibility []string
1233	}
1234}
1235
1236type mockParent struct {
1237	ModuleBase
1238	DefaultableModuleBase
1239	properties mockParentProperties
1240}
1241
1242func (p *mockParent) GenerateAndroidBuildActions(ModuleContext) {
1243}
1244
1245func newMockParentFactory() Module {
1246	m := &mockParent{}
1247	m.AddProperties(&m.properties)
1248	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
1249	InitDefaultableModule(m)
1250	AddVisibilityProperty(m, "child.visibility", &m.properties.Child.Visibility)
1251
1252	m.SetDefaultableHook(func(ctx DefaultableHookContext) {
1253		visibility := m.properties.Child.Visibility
1254		visibility = append(visibility, m.properties.Child.Invalid_visibility...)
1255		ctx.CreateModule(newMockLibraryModule, &struct {
1256			Name       *string
1257			Visibility []string
1258		}{m.properties.Child.Name, visibility})
1259	})
1260	return m
1261}
1262
1263func testVisibilityRuleSet(t *testing.T, rules, extra, expected []string) {
1264	t.Helper()
1265	set := &visibilityRuleSet{rules}
1266	err := set.Widen(extra)
1267	if err != nil {
1268		t.Error(err)
1269		return
1270	}
1271	actual := set.Strings()
1272	if !reflect.DeepEqual(actual, expected) {
1273		t.Errorf("mismatching rules after extend: expected %#v, actual %#v", expected, actual)
1274	}
1275}
1276
1277func TestVisibilityRuleSet(t *testing.T) {
1278	t.Run("extend empty", func(t *testing.T) {
1279		testVisibilityRuleSet(t, nil, []string{"//foo"}, []string{"//foo"})
1280	})
1281	t.Run("extend", func(t *testing.T) {
1282		testVisibilityRuleSet(t, []string{"//foo"}, []string{"//bar"}, []string{"//bar", "//foo"})
1283	})
1284	t.Run("extend duplicate", func(t *testing.T) {
1285		testVisibilityRuleSet(t, []string{"//foo"}, []string{"//bar", "//foo"}, []string{"//bar", "//foo"})
1286	})
1287	t.Run("extend public", func(t *testing.T) {
1288		testVisibilityRuleSet(t, []string{"//visibility:public"}, []string{"//foo"}, []string{"//visibility:public"})
1289	})
1290	t.Run("extend private", func(t *testing.T) {
1291		testVisibilityRuleSet(t, []string{"//visibility:private"}, []string{"//foo"}, []string{"//foo"})
1292	})
1293	t.Run("extend with public", func(t *testing.T) {
1294		testVisibilityRuleSet(t, []string{"//foo"}, []string{"//visibility:public"}, []string{"//visibility:public"})
1295	})
1296	t.Run("extend with private", func(t *testing.T) {
1297		t.Helper()
1298		set := &visibilityRuleSet{[]string{"//foo"}}
1299		err := set.Widen([]string{"//visibility:private"})
1300		expectedError := `"//visibility:private" does not widen the visibility`
1301		if err == nil {
1302			t.Errorf("missing error")
1303		} else if err.Error() != expectedError {
1304			t.Errorf("expected error %q found error %q", expectedError, err)
1305		}
1306	})
1307}
1308