2019-03-28 15:10:57 +01:00
package android
import (
2020-02-19 17:10:09 +01:00
"reflect"
2019-03-28 15:10:57 +01:00
"testing"
2019-05-21 13:18:38 +02:00
"github.com/google/blueprint"
2019-03-28 15:10:57 +01:00
)
var visibilityTests = [ ] struct {
2020-02-19 17:10:09 +01:00
name string
fs map [ string ] [ ] byte
expectedErrors [ ] string
effectiveVisibility map [ qualifiedModuleName ] [ ] string
2019-03-28 15:10:57 +01:00
} {
{
name : "invalid visibility: empty list" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: must contain at least one visibility rule ` } ,
} ,
{
name : "invalid visibility: empty rule" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: invalid visibility pattern "" ` } ,
} ,
{
name : "invalid visibility: unqualified" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "target" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: invalid visibility pattern "target" ` } ,
} ,
{
name : "invalid visibility: empty namespace" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: invalid visibility pattern "//" ` } ,
} ,
{
name : "invalid visibility: empty module" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ ":" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: invalid visibility pattern ":" ` } ,
} ,
{
name : "invalid visibility: empty namespace and module" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//:" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` visibility: invalid visibility pattern "//:" ` } ,
} ,
{
name : "//visibility:unknown" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//visibility:unknown" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` unrecognized visibility rule "//visibility:unknown" ` } ,
} ,
{
2019-05-17 23:42:02 +02:00
name : "//visibility:xxx mixed" ,
2019-03-28 15:10:57 +01:00
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//visibility:public" , "//namespace" ] ,
}
mock_library {
name : "libother" ,
visibility : [ "//visibility:private" , "//namespace" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
2019-05-17 23:42:02 +02:00
` module "libother": visibility: cannot mix "//visibility:private" ` +
` with any other visibility rules ` ,
` module "libexample": visibility: cannot mix "//visibility:public" ` +
2019-03-28 15:10:57 +01:00
` with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:legacy_public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//visibility:legacy_public" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
2019-05-17 23:42:02 +02:00
` module "libexample": visibility: //visibility:legacy_public must ` +
2019-03-28 15:10:57 +01:00
` not be used ` ,
} ,
} ,
{
// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
// the current directory, a nested directory and a directory in a separate tree.
name : "//visibility:public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
// Verify that //visibility:private allows the module to be referenced from the current
// directory only.
name : "//visibility:private" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
2019-05-21 13:18:38 +02:00
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
2019-03-28 15:10:57 +01:00
} ,
expectedErrors : [ ] string {
` module "libnested" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-05-21 13:18:38 +02:00
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
} ,
} ,
{
// Verify that :__pkg__ allows the module to be referenced from the current directory only.
name : ":__pkg__" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ ":__pkg__" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
2019-05-21 13:18:38 +02:00
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
2019-03-28 15:10:57 +01:00
} ,
expectedErrors : [ ] string {
` module "libnested" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-05-21 13:18:38 +02:00
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
} ,
} ,
{
// Verify that //top/nested allows the module to be referenced from the current directory and
// the top/nested directory only, not a subdirectory of top/nested and not peak directory.
name : "//top/nested" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//top/nested" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/again/Blueprints" : [ ] byte ( `
mock_library {
name : "libnestedagain" ,
deps : [ "libexample" ] ,
} ` ) ,
"peak/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
` module "libnestedagain" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
} ,
} ,
{
// Verify that :__subpackages__ allows the module to be referenced from the current directory
// and sub directories but nowhere else.
name : ":__subpackages__" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ ":__subpackages__" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"peak/other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
} ,
} ,
{
// Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
// directory and sub directories but nowhere else.
name : "//top/nested:__subpackages__" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//top/nested:__subpackages__" , "//other" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
2019-05-17 23:42:02 +02:00
` visible to this module ` ,
2019-03-28 15:10:57 +01:00
} ,
} ,
{
// Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
// the current directory, top/nested and peak and all its subpackages.
name : ` ["//top/nested", "//peak:__subpackages__"] ` ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//top/nested" , "//peak:__subpackages__" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"peak/other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
// Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
name : ` //vendor ` ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//vendor:__subpackages__" ] ,
}
mock_library {
name : "libsamepackage" ,
visibility : [ "//vendor/apps/AcmeSettings" ] ,
} ` ) ,
"vendor/Blueprints" : [ ] byte ( `
mock_library {
name : "libvendorexample" ,
deps : [ "libexample" ] ,
visibility : [ "//vendor/nested" ] ,
} ` ) ,
"vendor/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libvendornested" ,
deps : [ "libexample" , "libvendorexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
2019-05-17 23:42:02 +02:00
` module "libsamepackage": visibility: "//vendor/apps/AcmeSettings" ` +
2019-03-28 15:10:57 +01:00
` is not allowed. Packages outside //vendor cannot make themselves visible to specific ` +
` targets within //vendor, they can only use //vendor:__subpackages__. ` ,
} ,
} ,
2019-05-17 23:42:02 +02:00
// Defaults propagation tests
{
// Check that visibility is the union of the defaults modules.
name : "defaults union, basic" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//other" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//top/nested" ] ,
defaults : [ "libexample_defaults" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "defaults union, multiple defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults_1" ,
visibility : [ "//other" ] ,
}
mock_defaults {
name : "libexample_defaults_2" ,
visibility : [ "//top/nested" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults_1" , "libexample_defaults_2" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "//visibility:public mixed with other in defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:public" , "//namespace" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample_defaults": visibility: cannot mix "//visibility:public" ` +
` with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:public overriding defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//namespace" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:public" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
2020-02-19 17:10:09 +01:00
effectiveVisibility : map [ qualifiedModuleName ] [ ] string {
qualifiedModuleName { pkg : "top" , name : "libexample" } : { "//visibility:public" } ,
} ,
2019-05-17 23:42:02 +02:00
} ,
{
name : "//visibility:public mixed with other from different defaults 1" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults_1" ,
visibility : [ "//namespace" ] ,
}
mock_defaults {
name : "libexample_defaults_2" ,
visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults_1" , "libexample_defaults_2" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
name : "//visibility:public mixed with other from different defaults 2" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults_1" ,
visibility : [ "//visibility:public" ] ,
}
mock_defaults {
name : "libexample_defaults_2" ,
visibility : [ "//namespace" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults_1" , "libexample_defaults_2" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
name : "//visibility:private in defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults" ] ,
}
mock_library {
name : "libsamepackage" ,
deps : [ "libexample" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libnested" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
` module "libother" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "//visibility:private mixed with other in defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" , "//namespace" ] ,
}
mock_library {
name : "libexample" ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample_defaults": visibility: cannot mix "//visibility:private" ` +
` with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:private overriding defaults" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//namespace" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:private" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample": visibility: cannot mix "//visibility:private" ` +
` with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:private in defaults overridden" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//namespace" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample": visibility: cannot mix "//visibility:private" ` +
` with any other visibility rules ` ,
} ,
} ,
2020-05-05 20:19:22 +02:00
{
name : "//visibility:private override //visibility:public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:private" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample": visibility: cannot mix "//visibility:private" with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:public override //visibility:private" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:public" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample": visibility: cannot mix "//visibility:private" with any other visibility rules ` ,
} ,
} ,
{
name : "//visibility:override must be first in the list" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_library {
name : "libexample" ,
visibility : [ "//other" , "//visibility:override" , "//namespace" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libexample": visibility: "//visibility:override" may only be used at the start of the visibility rules ` ,
} ,
} ,
{
name : "//visibility:override discards //visibility:private" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
// Make this visibility to //other but not //visibility:private
visibility : [ "//visibility:override" , "//other" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
name : "//visibility:override discards //visibility:public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libexample" ,
// Make this visibility to //other but not //visibility:public
visibility : [ "//visibility:override" , "//other" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
"namespace/Blueprints" : [ ] byte ( `
mock_library {
name : "libnamespace" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
2020-10-15 20:46:38 +02:00
` 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 ` ,
2020-05-05 20:19:22 +02:00
} ,
} ,
{
name : "//visibility:override discards defaults supplied rules" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//namespace" ] ,
}
mock_library {
name : "libexample" ,
// Make this visibility to //other but not //namespace
visibility : [ "//visibility:override" , "//other" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libexample" ] ,
} ` ) ,
"namespace/Blueprints" : [ ] byte ( `
mock_library {
name : "libnamespace" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
2020-10-15 20:46:38 +02:00
` 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 ` ,
2020-05-05 20:19:22 +02:00
} ,
} ,
{
name : "//visibility:override can override //visibility:public with //visibility:private" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:override" , "//visibility:private" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"namespace/Blueprints" : [ ] byte ( `
mock_library {
name : "libnamespace" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "libnamespace" variant "android_common": depends on //top:libexample which is not visible to this module ` ,
} ,
} ,
{
name : "//visibility:override can override //visibility:private with //visibility:public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:override" , "//visibility:public" ] ,
defaults : [ "libexample_defaults" ] ,
} ` ) ,
"namespace/Blueprints" : [ ] byte ( `
mock_library {
name : "libnamespace" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
2019-05-17 23:42:02 +02:00
{
name : "//visibility:private mixed with itself" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "libexample_defaults_1" ,
visibility : [ "//visibility:private" ] ,
}
mock_defaults {
name : "libexample_defaults_2" ,
visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:private" ] ,
defaults : [ "libexample_defaults_1" , "libexample_defaults_2" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
2019-07-24 14:45:05 +02:00
// Defaults module's defaults_visibility tests
{
name : "defaults_visibility invalid" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_defaults {
name : "top_defaults" ,
defaults_visibility : [ "//visibility:invalid" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` defaults_visibility: unrecognized visibility rule "//visibility:invalid" ` ,
} ,
} ,
{
name : "defaults_visibility overrides package default" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:private" ] ,
}
mock_defaults {
name : "top_defaults" ,
defaults_visibility : [ "//visibility:public" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
defaults : [ "top_defaults" ] ,
} ` ) ,
} ,
} ,
2019-05-31 15:00:04 +02:00
// Package default_visibility tests
{
name : "package default_visibility property is checked" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:invalid" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string { ` default_visibility: unrecognized visibility rule "//visibility:invalid" ` } ,
} ,
{
// This test relies on the default visibility being legacy_public.
name : "package default_visibility property used when no visibility specified" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "package default_visibility public does not override visibility private" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:public" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:private" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "package default_visibility private does not override visibility public" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:private" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ "//visibility:public" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
} ,
{
name : "package default_visibility :__subpackages__" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ ":__subpackages__" ] ,
}
mock_library {
name : "libexample" ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
2019-06-20 17:38:08 +02:00
{
name : "package default_visibility inherited to subpackages" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//outsider" ] ,
}
mock_library {
name : "libexample" ,
visibility : [ ":__subpackages__" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libexample" ] ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libexample" , "libnested" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top:libexample which is not ` +
` visible to this module ` ,
} ,
} ,
{
name : "package default_visibility inherited to subpackages" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//visibility:private" ] ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
package {
default_visibility : [ "//outsider" ] ,
}
mock_library {
name : "libnested" ,
} ` ) ,
"top/other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
} ` ) ,
"outsider/Blueprints" : [ ] byte ( `
mock_library {
name : "liboutsider" ,
deps : [ "libother" , "libnested" ] ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "liboutsider" variant "android_common": depends on //top/other:libother which is ` +
` not visible to this module ` ,
} ,
} ,
2020-01-14 13:42:08 +01:00
{
name : "verify that prebuilt dependencies are ignored for visibility reasons (not preferred)" ,
fs : map [ string ] [ ] byte {
"prebuilts/Blueprints" : [ ] byte ( `
prebuilt {
name : "module" ,
visibility : [ "//top/other" ] ,
} ` ) ,
"top/sources/source_file" : nil ,
"top/sources/Blueprints" : [ ] byte ( `
source {
name : "module" ,
visibility : [ "//top/other" ] ,
} ` ) ,
"top/other/source_file" : nil ,
"top/other/Blueprints" : [ ] byte ( `
source {
name : "other" ,
deps : [ ":module" ] ,
} ` ) ,
} ,
} ,
{
name : "verify that prebuilt dependencies are ignored for visibility reasons (preferred)" ,
fs : map [ string ] [ ] byte {
"prebuilts/Blueprints" : [ ] byte ( `
prebuilt {
name : "module" ,
visibility : [ "//top/other" ] ,
prefer : true ,
} ` ) ,
"top/sources/source_file" : nil ,
"top/sources/Blueprints" : [ ] byte ( `
source {
name : "module" ,
visibility : [ "//top/other" ] ,
} ` ) ,
"top/other/source_file" : nil ,
"top/other/Blueprints" : [ ] byte ( `
source {
name : "other" ,
deps : [ ":module" ] ,
} ` ) ,
} ,
} ,
2020-04-29 17:47:28 +02:00
{
name : "ensure visibility properties are checked for correctness" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_parent {
name : "parent" ,
visibility : [ "//top/nested" ] ,
child : {
name : "libchild" ,
visibility : [ "top/other" ] ,
} ,
} ` ) ,
} ,
expectedErrors : [ ] string {
` module "parent": child.visibility: invalid visibility pattern "top/other" ` ,
} ,
} ,
{
name : "invalid visibility added to child detected during gather phase" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_parent {
name : "parent" ,
visibility : [ "//top/nested" ] ,
child : {
name : "libchild" ,
invalid_visibility : [ "top/other" ] ,
} ,
} ` ) ,
} ,
expectedErrors : [ ] string {
// That this error is reported against the child not the parent shows it was
// not being detected in the parent which is correct as invalid_visibility is
// purposely not added to the list of visibility properties to check, and was
// in fact detected in the child in the gather phase. Contrast this error message
// with the preceding one.
` module "libchild" \(created by module "parent"\): visibility: invalid visibility pattern "top/other" ` ,
} ,
} ,
{
name : "automatic visibility inheritance enabled" ,
fs : map [ string ] [ ] byte {
"top/Blueprints" : [ ] byte ( `
mock_parent {
name : "parent" ,
visibility : [ "//top/nested" ] ,
child : {
name : "libchild" ,
visibility : [ "//top/other" ] ,
} ,
} ` ) ,
"top/nested/Blueprints" : [ ] byte ( `
mock_library {
name : "libnested" ,
deps : [ "libchild" ] ,
} ` ) ,
"top/other/Blueprints" : [ ] byte ( `
mock_library {
name : "libother" ,
deps : [ "libchild" ] ,
} ` ) ,
} ,
} ,
2019-03-28 15:10:57 +01:00
}
func TestVisibility ( t * testing . T ) {
for _ , test := range visibilityTests {
t . Run ( test . name , func ( t * testing . T ) {
2020-02-19 17:10:09 +01:00
ctx , errs := testVisibility ( buildDir , test . fs )
2019-03-28 15:10:57 +01:00
2019-08-05 16:07:57 +02:00
CheckErrorsAgainstExpectations ( t , errs , test . expectedErrors )
2020-02-19 17:10:09 +01:00
if test . effectiveVisibility != nil {
checkEffectiveVisibility ( t , ctx , test . effectiveVisibility )
}
2019-03-28 15:10:57 +01:00
} )
}
}
2020-02-19 17:10:09 +01:00
func checkEffectiveVisibility ( t * testing . T , ctx * TestContext , effectiveVisibility map [ qualifiedModuleName ] [ ] string ) {
for moduleName , expectedRules := range effectiveVisibility {
rule := effectiveVisibilityRules ( ctx . config , moduleName )
stringRules := rule . Strings ( )
if ! reflect . DeepEqual ( expectedRules , stringRules ) {
t . Errorf ( "effective rules mismatch: expected %q, found %q" , expectedRules , stringRules )
}
}
}
2019-03-28 15:10:57 +01:00
func testVisibility ( buildDir string , fs map [ string ] [ ] byte ) ( * TestContext , [ ] error ) {
// Create a new config per test as visibility information is stored in the config.
2019-12-14 05:41:13 +01:00
config := TestArchConfig ( buildDir , nil , "" , fs )
2019-03-28 15:10:57 +01:00
ctx := NewTestArchContext ( )
2019-11-23 00:25:03 +01:00
ctx . RegisterModuleType ( "mock_library" , newMockLibraryModule )
2020-04-29 17:47:28 +02:00
ctx . RegisterModuleType ( "mock_parent" , newMockParentFactory )
2019-11-23 00:25:03 +01:00
ctx . RegisterModuleType ( "mock_defaults" , defaultsFactory )
2020-01-14 13:42:08 +01:00
// Order of the following method calls is significant.
2020-01-14 13:15:29 +01:00
RegisterPackageBuildComponents ( ctx )
2020-01-14 13:42:08 +01:00
registerTestPrebuiltBuildComponents ( ctx )
2019-12-05 15:31:48 +01:00
ctx . PreArchMutators ( RegisterVisibilityRuleChecker )
2019-05-17 23:42:02 +02:00
ctx . PreArchMutators ( RegisterDefaultsPreArchMutators )
2019-12-05 15:31:48 +01:00
ctx . PreArchMutators ( RegisterVisibilityRuleGatherer )
ctx . PostDepsMutators ( RegisterVisibilityRuleEnforcer )
2019-12-14 05:41:13 +01:00
ctx . Register ( config )
2019-03-28 15:10:57 +01:00
_ , errs := ctx . ParseBlueprintsFiles ( "." )
if len ( errs ) > 0 {
return ctx , errs
}
_ , errs = ctx . PrepareBuildActions ( config )
return ctx , errs
}
type mockLibraryProperties struct {
Deps [ ] string
}
type mockLibraryModule struct {
ModuleBase
2019-05-17 23:42:02 +02:00
DefaultableModuleBase
2019-03-28 15:10:57 +01:00
properties mockLibraryProperties
}
func newMockLibraryModule ( ) Module {
m := & mockLibraryModule { }
m . AddProperties ( & m . properties )
InitAndroidArchModule ( m , HostAndDeviceSupported , MultilibCommon )
2019-05-17 23:42:02 +02:00
InitDefaultableModule ( m )
2019-03-28 15:10:57 +01:00
return m
}
type dependencyTag struct {
blueprint . BaseDependencyTag
name string
}
func ( j * mockLibraryModule ) DepsMutator ( ctx BottomUpMutatorContext ) {
ctx . AddVariationDependencies ( nil , dependencyTag { name : "mockdeps" } , j . properties . Deps ... )
}
func ( p * mockLibraryModule ) GenerateAndroidBuildActions ( ModuleContext ) {
}
2019-05-17 23:42:02 +02:00
type mockDefaults struct {
ModuleBase
DefaultsModuleBase
}
func defaultsFactory ( ) Module {
m := & mockDefaults { }
InitDefaultsModule ( m )
return m
}
2020-04-29 17:47:28 +02:00
type mockParentProperties struct {
Child struct {
Name * string
// Visibility to pass to the child module.
Visibility [ ] string
// Purposely not validated visibility to pass to the child.
Invalid_visibility [ ] string
}
}
type mockParent struct {
ModuleBase
DefaultableModuleBase
properties mockParentProperties
}
func ( p * mockParent ) GenerateAndroidBuildActions ( ModuleContext ) {
}
func newMockParentFactory ( ) Module {
m := & mockParent { }
m . AddProperties ( & m . properties )
InitAndroidArchModule ( m , HostAndDeviceSupported , MultilibCommon )
InitDefaultableModule ( m )
AddVisibilityProperty ( m , "child.visibility" , & m . properties . Child . Visibility )
m . SetDefaultableHook ( func ( ctx DefaultableHookContext ) {
visibility := m . properties . Child . Visibility
visibility = append ( visibility , m . properties . Child . Invalid_visibility ... )
ctx . CreateModule ( newMockLibraryModule , & struct {
Name * string
Visibility [ ] string
} { m . properties . Child . Name , visibility } )
} )
return m
}
2020-09-29 17:01:08 +02:00
func testVisibilityRuleSet ( t * testing . T , rules , extra , expected [ ] string ) {
t . Helper ( )
set := & visibilityRuleSet { rules }
err := set . Widen ( extra )
if err != nil {
t . Error ( err )
return
}
actual := set . Strings ( )
if ! reflect . DeepEqual ( actual , expected ) {
t . Errorf ( "mismatching rules after extend: expected %#v, actual %#v" , expected , actual )
}
}
func TestVisibilityRuleSet ( t * testing . T ) {
t . Run ( "extend empty" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , nil , [ ] string { "//foo" } , [ ] string { "//foo" } )
} )
t . Run ( "extend" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , [ ] string { "//foo" } , [ ] string { "//bar" } , [ ] string { "//bar" , "//foo" } )
} )
t . Run ( "extend duplicate" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , [ ] string { "//foo" } , [ ] string { "//bar" , "//foo" } , [ ] string { "//bar" , "//foo" } )
} )
t . Run ( "extend public" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , [ ] string { "//visibility:public" } , [ ] string { "//foo" } , [ ] string { "//visibility:public" } )
} )
t . Run ( "extend private" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , [ ] string { "//visibility:private" } , [ ] string { "//foo" } , [ ] string { "//foo" } )
} )
t . Run ( "extend with public" , func ( t * testing . T ) {
testVisibilityRuleSet ( t , [ ] string { "//foo" } , [ ] string { "//visibility:public" } , [ ] string { "//visibility:public" } )
} )
t . Run ( "extend with private" , func ( t * testing . T ) {
t . Helper ( )
set := & visibilityRuleSet { [ ] string { "//foo" } }
err := set . Widen ( [ ] string { "//visibility:private" } )
expectedError := ` "//visibility:private" does not widen the visibility `
if err == nil {
t . Errorf ( "missing error" )
} else if err . Error ( ) != expectedError {
t . Errorf ( "expected error %q found error %q" , expectedError , err )
}
} )
}