2019-01-25 06:58:11 +08:00
|
|
|
// Copyright 2019 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"
|
2019-10-17 04:06:07 +08:00
|
|
|
"runtime"
|
2019-01-25 06:58:11 +08:00
|
|
|
"testing"
|
2019-09-26 02:26:40 +08:00
|
|
|
|
|
|
|
"github.com/google/blueprint/proptools"
|
2019-01-25 06:58:11 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type Named struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
B *string
|
|
|
|
}
|
|
|
|
|
|
|
|
type NamedAllFiltered struct {
|
|
|
|
A *string
|
|
|
|
}
|
|
|
|
|
|
|
|
type NamedNoneFiltered struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFilterArchStruct(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
in interface{}
|
|
|
|
out interface{}
|
|
|
|
filtered bool
|
|
|
|
}{
|
|
|
|
// Property tests
|
|
|
|
{
|
|
|
|
name: "basic",
|
|
|
|
in: &struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
B *string
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *string
|
|
|
|
}{},
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "all filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *string
|
|
|
|
}{},
|
|
|
|
out: nil,
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "none filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
filtered: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Sub-struct tests
|
|
|
|
{
|
|
|
|
name: "substruct",
|
|
|
|
in: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
B *string
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "substruct all filtered",
|
|
|
|
in: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: nil,
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "substruct none filtered",
|
|
|
|
in: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
filtered: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Named sub-struct tests
|
|
|
|
{
|
|
|
|
name: "named substruct",
|
|
|
|
in: &struct {
|
|
|
|
A Named `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A struct {
|
|
|
|
A *string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "substruct all filtered",
|
|
|
|
in: &struct {
|
|
|
|
A NamedAllFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: nil,
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "substruct none filtered",
|
|
|
|
in: &struct {
|
|
|
|
A NamedNoneFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A NamedNoneFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
filtered: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Pointer to sub-struct tests
|
|
|
|
{
|
|
|
|
name: "pointer substruct",
|
|
|
|
in: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
B *string
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "pointer substruct all filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: nil,
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "pointer substruct none filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string `android:"arch_variant"`
|
|
|
|
} `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
filtered: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Pointer to named sub-struct tests
|
|
|
|
{
|
|
|
|
name: "pointer named substruct",
|
|
|
|
in: &struct {
|
|
|
|
A *Named `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *struct {
|
|
|
|
A *string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "pointer substruct all filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *NamedAllFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: nil,
|
|
|
|
filtered: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "pointer substruct none filtered",
|
|
|
|
in: &struct {
|
|
|
|
A *NamedNoneFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
out: &struct {
|
|
|
|
A *NamedNoneFiltered `android:"arch_variant"`
|
|
|
|
}{},
|
|
|
|
filtered: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
2019-09-26 02:26:40 +08:00
|
|
|
out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct)
|
2019-01-25 06:58:11 +08:00
|
|
|
if filtered != test.filtered {
|
|
|
|
t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
|
|
|
|
}
|
|
|
|
expected := reflect.TypeOf(test.out)
|
|
|
|
if out != expected {
|
|
|
|
t.Errorf("expected type %v, got %v", expected, out)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2019-10-17 04:06:07 +08:00
|
|
|
|
|
|
|
type archTestModule struct {
|
|
|
|
ModuleBase
|
|
|
|
props struct {
|
|
|
|
Deps []string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) {
|
|
|
|
ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func archTestModuleFactory() Module {
|
|
|
|
m := &archTestModule{}
|
|
|
|
m.AddProperties(&m.props)
|
|
|
|
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestArchMutator(t *testing.T) {
|
|
|
|
var buildOSVariants []string
|
|
|
|
var buildOS32Variants []string
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "linux":
|
|
|
|
buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"}
|
|
|
|
buildOS32Variants = []string{"linux_glibc_x86"}
|
|
|
|
case "darwin":
|
|
|
|
buildOSVariants = []string{"darwin_x86_64"}
|
|
|
|
buildOS32Variants = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
bp := `
|
|
|
|
module {
|
|
|
|
name: "foo",
|
|
|
|
}
|
|
|
|
|
|
|
|
module {
|
|
|
|
name: "bar",
|
|
|
|
host_supported: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
module {
|
|
|
|
name: "baz",
|
|
|
|
device_supported: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
module {
|
|
|
|
name: "qux",
|
|
|
|
host_supported: true,
|
|
|
|
compile_multilib: "32",
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
config func(Config)
|
|
|
|
fooVariants []string
|
|
|
|
barVariants []string
|
|
|
|
bazVariants []string
|
|
|
|
quxVariants []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "normal",
|
|
|
|
config: nil,
|
|
|
|
fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
|
|
|
|
barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
|
|
|
|
bazVariants: nil,
|
|
|
|
quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "host-only",
|
|
|
|
config: func(config Config) {
|
|
|
|
config.BuildOSTarget = Target{}
|
|
|
|
config.BuildOSCommonTarget = Target{}
|
|
|
|
config.Targets[Android] = nil
|
|
|
|
},
|
|
|
|
fooVariants: nil,
|
|
|
|
barVariants: buildOSVariants,
|
|
|
|
bazVariants: nil,
|
|
|
|
quxVariants: buildOS32Variants,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
enabledVariants := func(ctx *TestContext, name string) []string {
|
|
|
|
var ret []string
|
|
|
|
variants := ctx.ModuleVariantsForTests(name)
|
|
|
|
for _, variant := range variants {
|
|
|
|
m := ctx.ModuleForTests(name, variant)
|
|
|
|
if m.Module().Enabled() {
|
|
|
|
ret = append(ret, variant)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range testCases {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2019-12-14 12:41:13 +08:00
|
|
|
config := TestArchConfig(buildDir, nil, bp, nil)
|
|
|
|
|
2019-10-17 04:06:07 +08:00
|
|
|
ctx := NewTestArchContext()
|
2019-11-23 07:25:03 +08:00
|
|
|
ctx.RegisterModuleType("module", archTestModuleFactory)
|
2019-12-14 12:41:13 +08:00
|
|
|
ctx.Register(config)
|
2019-10-17 04:06:07 +08:00
|
|
|
if tt.config != nil {
|
|
|
|
tt.config(config)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
|
|
|
FailIfErrored(t, errs)
|
|
|
|
_, errs = ctx.PrepareBuildActions(config)
|
|
|
|
FailIfErrored(t, errs)
|
|
|
|
|
|
|
|
if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
|
|
|
|
t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
|
|
|
|
t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
|
|
|
|
t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) {
|
|
|
|
t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|