blob: b3911036a8a9fb8a63ac891491853699a1cb62b2 [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.
28 Test_config *string `android:"arch_variant"`
29
30 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that
31 // should be installed with the module.
32 Test_config_template *string `android:"arch_variant"`
33
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
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070053func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070054 module := newModule(hod, android.MultilibFirst)
55
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070056 test := &testDecorator{
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070057 binaryDecorator: &binaryDecorator{
58 // TODO(chh): set up dir64?
59 baseCompiler: NewBaseCompiler("testcases", ""),
60 },
61 }
62
63 module.compiler = test
64
65 return module, test
66}
67
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070068func (test *testDecorator) compilerProps() []interface{} {
69 return append(test.binaryDecorator.compilerProps(), &test.Properties)
70}
71
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080072func (test *testDecorator) getMutatedModuleSubName(moduleName string) string {
73 stem := String(test.baseCompiler.Properties.Stem)
74 if stem != "" && !strings.HasSuffix(moduleName, "_"+stem) {
75 // Avoid repeated suffix in the module name.
76 return "_" + stem
77 }
78 return ""
79}
80
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070081func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
82 name := ctx.ModuleName() // default executable name
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080083 if ctx.Device() { // on device, use mutated module name
84 name = name + test.getMutatedModuleSubName(name)
85 } else { // on host, use stem name in relative_install_path
86 if stem := String(test.baseCompiler.Properties.Stem); stem != "" {
87 name = stem
88 }
89 if path := test.baseCompiler.relativeInstallPath(); path != "" {
90 name = path + "/" + name
91 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070092 }
Chih-Hung Hsiehede57ae2019-11-22 20:22:35 -080093 test.testConfig = tradefed.AutoGenRustTestConfig(ctx, name,
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070094 test.Properties.Test_config,
95 test.Properties.Test_config_template,
96 test.Properties.Test_suites,
97 test.Properties.Auto_gen_config)
98 test.binaryDecorator.install(ctx, file)
99}
100
101func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700102 flags = test.binaryDecorator.compilerFlags(ctx, flags)
103 flags.RustFlags = append(flags.RustFlags, "--test")
104 return flags
105}
106
107func init() {
108 // Rust tests are binary files built with --test.
109 android.RegisterModuleType("rust_test", RustTestFactory)
110 android.RegisterModuleType("rust_test_host", RustTestHostFactory)
111}
112
113func RustTestFactory() android.Module {
114 module, _ := NewRustTest(android.HostAndDeviceSupported)
115 return module.Init()
116}
117
118func RustTestHostFactory() android.Module {
119 module, _ := NewRustTest(android.HostSupported)
120 return module.Init()
121}
122
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700123func (test *testDecorator) testPerSrc() bool {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700124 return true
125}
126
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700127func (test *testDecorator) srcs() []string {
128 return test.binaryDecorator.Properties.Srcs
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700129}
130
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700131func (test *testDecorator) setSrc(name, src string) {
132 test.binaryDecorator.Properties.Srcs = []string{src}
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700133 test.baseCompiler.Properties.Stem = StringPtr(name)
134}
135
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700136func (test *testDecorator) unsetSrc() {
137 test.binaryDecorator.Properties.Srcs = nil
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700138 test.baseCompiler.Properties.Stem = StringPtr("")
139}
140
141type testPerSrc interface {
142 testPerSrc() bool
143 srcs() []string
144 setSrc(string, string)
145 unsetSrc()
146}
147
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700148var _ testPerSrc = (*testDecorator)(nil)
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700149
150func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
151 if m, ok := mctx.Module().(*Module); ok {
152 if test, ok := m.compiler.(testPerSrc); ok {
153 numTests := len(test.srcs())
154 if test.testPerSrc() && numTests > 0 {
155 if duplicate, found := android.CheckDuplicate(test.srcs()); found {
156 mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
157 return
158 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700159 // Rust compiler always compiles one source file at a time and
160 // uses the crate name as output file name.
161 // Cargo uses the test source file name as default crate name,
162 // but that can be redefined.
163 // So when there are multiple source files, the source file names will
164 // be the output file names, but when there is only one test file,
165 // use the crate name.
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700166 testNames := make([]string, numTests)
167 for i, src := range test.srcs() {
168 testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
169 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700170 crateName := m.compiler.crateName()
171 if numTests == 1 && crateName != "" {
172 testNames[0] = crateName
173 }
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700174 // TODO(chh): Add an "all tests" variation like cc/test.go?
175 tests := mctx.CreateLocalVariations(testNames...)
176 for i, src := range test.srcs() {
177 tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
178 }
179 }
180 }
181 }
182}