eabaedd520
Product variables structs are generated at runtime to contain only the properties that apply to the current module. Defaults modules always contained all product variable properties. Defaults modules apply their properties to the target module using proptools.PrependProperties, which prepends structs that have matching types. Filtered property structs had a different type and were dropped. Even after adding filtering to the defaults product variable properties, defaults modules may contain more property structs than the target module they are applied to, so the product variables struct for the defaults module could contain more fields than the product variables struct for the target module. Use proptools.PrependMatchingProperties when applying defaults of product variables instead, which will apply matching properties across types. Test: defaults_test.go Test: variable_test.go Change-Id: I281bdefef92053457a3b7b65383493a4e7d999df
337 lines
7.2 KiB
Go
337 lines
7.2 KiB
Go
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
type printfIntoPropertyTestCase struct {
|
|
in string
|
|
val interface{}
|
|
out string
|
|
err bool
|
|
}
|
|
|
|
var printfIntoPropertyTestCases = []printfIntoPropertyTestCase{
|
|
{
|
|
in: "%d",
|
|
val: 0,
|
|
out: "0",
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: 1,
|
|
out: "1",
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: 2,
|
|
out: "2",
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: false,
|
|
out: "0",
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: true,
|
|
out: "1",
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: -1,
|
|
out: "-1",
|
|
},
|
|
|
|
{
|
|
in: "-DA=%d",
|
|
val: 1,
|
|
out: "-DA=1",
|
|
},
|
|
{
|
|
in: "-DA=%du",
|
|
val: 1,
|
|
out: "-DA=1u",
|
|
},
|
|
{
|
|
in: "-DA=%s",
|
|
val: "abc",
|
|
out: "-DA=abc",
|
|
},
|
|
{
|
|
in: `-DA="%s"`,
|
|
val: "abc",
|
|
out: `-DA="abc"`,
|
|
},
|
|
|
|
{
|
|
in: "%%",
|
|
err: true,
|
|
},
|
|
{
|
|
in: "%d%s",
|
|
err: true,
|
|
},
|
|
{
|
|
in: "%d,%s",
|
|
err: true,
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: "",
|
|
err: true,
|
|
},
|
|
{
|
|
in: "%d",
|
|
val: 1.5,
|
|
err: true,
|
|
},
|
|
{
|
|
in: "%f",
|
|
val: 1.5,
|
|
err: true,
|
|
},
|
|
}
|
|
|
|
func TestPrintfIntoProperty(t *testing.T) {
|
|
for _, testCase := range printfIntoPropertyTestCases {
|
|
s := testCase.in
|
|
v := reflect.ValueOf(&s).Elem()
|
|
err := printfIntoProperty(v, testCase.val)
|
|
if err != nil && !testCase.err {
|
|
t.Errorf("unexpected error %s", err)
|
|
} else if err == nil && testCase.err {
|
|
t.Errorf("expected error")
|
|
} else if err == nil && v.String() != testCase.out {
|
|
t.Errorf("expected %q got %q", testCase.out, v.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
type testProductVariableModule struct {
|
|
ModuleBase
|
|
}
|
|
|
|
func (m *testProductVariableModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
}
|
|
|
|
var testProductVariableProperties = struct {
|
|
Product_variables struct {
|
|
Eng struct {
|
|
Srcs []string
|
|
Cflags []string
|
|
}
|
|
}
|
|
}{}
|
|
|
|
func testProductVariableModuleFactoryFactory(props interface{}) func() Module {
|
|
return func() Module {
|
|
m := &testProductVariableModule{}
|
|
clonedProps := proptools.CloneProperties(reflect.ValueOf(props)).Interface()
|
|
m.AddProperties(clonedProps)
|
|
|
|
// Set a default soongConfigVariableProperties, this will be used as the input to the property struct filter
|
|
// for this test module.
|
|
m.variableProperties = testProductVariableProperties
|
|
InitAndroidModule(m)
|
|
return m
|
|
}
|
|
}
|
|
|
|
func TestProductVariables(t *testing.T) {
|
|
ctx := NewTestContext()
|
|
// A module type that has a srcs property but not a cflags property.
|
|
ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct {
|
|
Srcs []string
|
|
}{}))
|
|
// A module type that has a cflags property but not a srcs property.
|
|
ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct {
|
|
Cflags []string
|
|
}{}))
|
|
// A module type that does not have any properties that match product_variables.
|
|
ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
|
|
Foo []string
|
|
}{}))
|
|
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
|
|
ctx.BottomUp("variable", VariableMutator).Parallel()
|
|
})
|
|
|
|
// Test that a module can use one product variable even if it doesn't have all the properties
|
|
// supported by that product variable.
|
|
bp := `
|
|
module1 {
|
|
name: "foo",
|
|
product_variables: {
|
|
eng: {
|
|
srcs: ["foo.c"],
|
|
},
|
|
},
|
|
}
|
|
module2 {
|
|
name: "bar",
|
|
product_variables: {
|
|
eng: {
|
|
cflags: ["-DBAR"],
|
|
},
|
|
},
|
|
}
|
|
|
|
module3 {
|
|
name: "baz",
|
|
}
|
|
`
|
|
config := TestConfig(buildDir, nil, bp, nil)
|
|
config.TestProductVariables.Eng = proptools.BoolPtr(true)
|
|
|
|
ctx.Register(config)
|
|
|
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
|
FailIfErrored(t, errs)
|
|
_, errs = ctx.PrepareBuildActions(config)
|
|
FailIfErrored(t, errs)
|
|
}
|
|
|
|
var testProductVariableDefaultsProperties = struct {
|
|
Product_variables struct {
|
|
Eng struct {
|
|
Foo []string
|
|
Bar []string
|
|
}
|
|
}
|
|
}{}
|
|
|
|
type productVariablesDefaultsTestProperties struct {
|
|
Foo []string
|
|
}
|
|
|
|
type productVariablesDefaultsTestProperties2 struct {
|
|
Foo []string
|
|
Bar []string
|
|
}
|
|
|
|
type productVariablesDefaultsTestModule struct {
|
|
ModuleBase
|
|
DefaultableModuleBase
|
|
properties productVariablesDefaultsTestProperties
|
|
}
|
|
|
|
func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
ctx.Build(pctx, BuildParams{
|
|
Rule: Touch,
|
|
Output: PathForModuleOut(ctx, "out"),
|
|
})
|
|
}
|
|
|
|
func productVariablesDefaultsTestModuleFactory() Module {
|
|
module := &productVariablesDefaultsTestModule{}
|
|
module.AddProperties(&module.properties)
|
|
module.variableProperties = testProductVariableDefaultsProperties
|
|
InitAndroidModule(module)
|
|
InitDefaultableModule(module)
|
|
return module
|
|
}
|
|
|
|
type productVariablesDefaultsTestDefaults struct {
|
|
ModuleBase
|
|
DefaultsModuleBase
|
|
}
|
|
|
|
func productVariablesDefaultsTestDefaultsFactory() Module {
|
|
defaults := &productVariablesDefaultsTestDefaults{}
|
|
defaults.AddProperties(&productVariablesDefaultsTestProperties{})
|
|
defaults.AddProperties(&productVariablesDefaultsTestProperties2{})
|
|
defaults.variableProperties = testProductVariableDefaultsProperties
|
|
InitDefaultsModule(defaults)
|
|
return defaults
|
|
}
|
|
|
|
// Test a defaults module that supports more product variable properties than the target module.
|
|
func TestProductVariablesDefaults(t *testing.T) {
|
|
bp := `
|
|
defaults {
|
|
name: "defaults",
|
|
product_variables: {
|
|
eng: {
|
|
foo: ["product_variable_defaults"],
|
|
bar: ["product_variable_defaults"],
|
|
},
|
|
},
|
|
foo: ["defaults"],
|
|
bar: ["defaults"],
|
|
}
|
|
|
|
test {
|
|
name: "foo",
|
|
defaults: ["defaults"],
|
|
foo: ["module"],
|
|
product_variables: {
|
|
eng: {
|
|
foo: ["product_variable_module"],
|
|
},
|
|
},
|
|
}
|
|
`
|
|
|
|
config := TestConfig(buildDir, nil, bp, nil)
|
|
config.TestProductVariables.Eng = boolPtr(true)
|
|
|
|
ctx := NewTestContext()
|
|
|
|
ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
|
|
ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
|
|
|
|
ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
|
|
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
|
|
ctx.BottomUp("variable", VariableMutator).Parallel()
|
|
})
|
|
|
|
ctx.Register(config)
|
|
|
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
|
FailIfErrored(t, errs)
|
|
_, errs = ctx.PrepareBuildActions(config)
|
|
FailIfErrored(t, errs)
|
|
|
|
foo := ctx.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
|
|
|
|
want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"}
|
|
if g, w := foo.properties.Foo, want; !reflect.DeepEqual(g, w) {
|
|
t.Errorf("expected foo %q, got %q", w, g)
|
|
}
|
|
}
|
|
|
|
func BenchmarkSliceToTypeArray(b *testing.B) {
|
|
for _, n := range []int{1, 2, 4, 8, 100} {
|
|
var propStructs []interface{}
|
|
for i := 0; i < n; i++ {
|
|
propStructs = append(propStructs, &struct {
|
|
A *string
|
|
B string
|
|
}{})
|
|
|
|
}
|
|
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = sliceToTypeArray(propStructs)
|
|
}
|
|
})
|
|
}
|
|
}
|