blob: 10c278597cf571ea36fcbd74801c21701ad77da5 [file] [log] [blame]
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -07001// Copyright 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package rust
16
17import (
18 "path/filepath"
19 "strings"
20
21 "android/soong/android"
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070022 "android/soong/tradefed"
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070023)
24
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070025type TestProperties struct {
26 // the name of the test configuration (for example "AndroidTest.xml") that should be
27 // installed with the module.
Colin Crossa6384822020-06-09 15:09:22 -070028 Test_config *string `android:"path,arch_variant"`
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070029
30 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that
31 // should be installed with the module.
Colin Crossa6384822020-06-09 15:09:22 -070032 Test_config_template *string `android:"path,arch_variant"`
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070033
34 // list of compatibility suites (for example "cts", "vts") that the module should be
35 // installed into.
36 Test_suites []string `android:"arch_variant"`
37
38 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
39 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
40 // explicitly.
41 Auto_gen_config *bool
42}
43
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070044// A test module is a binary module with extra --test compiler flag
45// and different default installation directory.
46// In golang, inheriance is written as a component.
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070047type testDecorator struct {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070048 *binaryDecorator
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070049 Properties TestProperties
50 testConfig android.Path
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070051}
52
Ivan Lozanoa0cd8f92020-04-09 09:56:02 -040053func (test *testDecorator) nativeCoverage() bool {
54 return true
55}
56
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070057func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070058 module := newModule(hod, android.MultilibFirst)
59
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070060 test := &testDecorator{
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070061 binaryDecorator: &binaryDecorator{
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -080062 baseCompiler: NewBaseCompiler("nativetest", "nativetest64", InstallInData),
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070063 },
64 }
65
66 module.compiler = test
67
68 return module, test
69}
70
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070071func (test *testDecorator) compilerProps() []interface{} {
72 return append(test.binaryDecorator.compilerProps(), &test.Properties)
73}
74
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080075func (test *testDecorator) getMutatedModuleSubName(moduleName string) string {
76 stem := String(test.baseCompiler.Properties.Stem)
77 if stem != "" && !strings.HasSuffix(moduleName, "_"+stem) {
78 // Avoid repeated suffix in the module name.
79 return "_" + stem
80 }
81 return ""
82}
83
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070084func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -080085 name := ctx.ModuleName()
86 path := test.baseCompiler.relativeInstallPath()
87 // on device, use mutated module name
88 name = name + test.getMutatedModuleSubName(name)
89 if !ctx.Device() { // on host, use mutated module name + arch type + stem name
90 stem := String(test.baseCompiler.Properties.Stem)
91 if stem == "" {
92 stem = name
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080093 }
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -080094 name = filepath.Join(name, ctx.Arch().ArchType.String(), stem)
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070095 }
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080096 test.testConfig = tradefed.AutoGenRustTestConfig(ctx, name,
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070097 test.Properties.Test_config,
98 test.Properties.Test_config_template,
99 test.Properties.Test_suites,
100 test.Properties.Auto_gen_config)
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -0800101 // default relative install path is module name
102 if path == "" {
103 test.baseCompiler.relative = ctx.ModuleName()
104 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700105 test.binaryDecorator.install(ctx, file)
106}
107
108func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700109 flags = test.binaryDecorator.compilerFlags(ctx, flags)
110 flags.RustFlags = append(flags.RustFlags, "--test")
111 return flags
112}
113
114func init() {
115 // Rust tests are binary files built with --test.
116 android.RegisterModuleType("rust_test", RustTestFactory)
117 android.RegisterModuleType("rust_test_host", RustTestHostFactory)
118}
119
120func RustTestFactory() android.Module {
121 module, _ := NewRustTest(android.HostAndDeviceSupported)
122 return module.Init()
123}
124
125func RustTestHostFactory() android.Module {
126 module, _ := NewRustTest(android.HostSupported)
127 return module.Init()
128}
129
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700130func (test *testDecorator) testPerSrc() bool {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700131 return true
132}
133
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700134func (test *testDecorator) srcs() []string {
135 return test.binaryDecorator.Properties.Srcs
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700136}
137
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700138func (test *testDecorator) setSrc(name, src string) {
139 test.binaryDecorator.Properties.Srcs = []string{src}
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700140 test.baseCompiler.Properties.Stem = StringPtr(name)
141}
142
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700143func (test *testDecorator) unsetSrc() {
144 test.binaryDecorator.Properties.Srcs = nil
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700145 test.baseCompiler.Properties.Stem = StringPtr("")
146}
147
148type testPerSrc interface {
149 testPerSrc() bool
150 srcs() []string
151 setSrc(string, string)
152 unsetSrc()
153}
154
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700155var _ testPerSrc = (*testDecorator)(nil)
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700156
157func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
158 if m, ok := mctx.Module().(*Module); ok {
159 if test, ok := m.compiler.(testPerSrc); ok {
160 numTests := len(test.srcs())
161 if test.testPerSrc() && numTests > 0 {
162 if duplicate, found := android.CheckDuplicate(test.srcs()); found {
163 mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
164 return
165 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700166 // Rust compiler always compiles one source file at a time and
167 // uses the crate name as output file name.
168 // Cargo uses the test source file name as default crate name,
169 // but that can be redefined.
170 // So when there are multiple source files, the source file names will
171 // be the output file names, but when there is only one test file,
172 // use the crate name.
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700173 testNames := make([]string, numTests)
174 for i, src := range test.srcs() {
175 testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
176 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700177 crateName := m.compiler.crateName()
178 if numTests == 1 && crateName != "" {
179 testNames[0] = crateName
180 }
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700181 // TODO(chh): Add an "all tests" variation like cc/test.go?
182 tests := mctx.CreateLocalVariations(testNames...)
183 for i, src := range test.srcs() {
184 tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
185 }
186 }
187 }
188 }
189}