blob: cb64e8f835af81812f04f6b6d8b2578692eb5278 [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
72func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
73 name := ctx.ModuleName() // default executable name
74 if stem := String(test.baseCompiler.Properties.Stem); stem != "" {
75 name = stem
76 }
77 if path := test.baseCompiler.relativeInstallPath(); path != "" {
78 name = path + "/" + name
79 }
80 test.testConfig = tradefed.AutoGenRustHostTestConfig(ctx, name,
81 test.Properties.Test_config,
82 test.Properties.Test_config_template,
83 test.Properties.Test_suites,
84 test.Properties.Auto_gen_config)
85 test.binaryDecorator.install(ctx, file)
86}
87
88func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070089 flags = test.binaryDecorator.compilerFlags(ctx, flags)
90 flags.RustFlags = append(flags.RustFlags, "--test")
91 return flags
92}
93
94func init() {
95 // Rust tests are binary files built with --test.
96 android.RegisterModuleType("rust_test", RustTestFactory)
97 android.RegisterModuleType("rust_test_host", RustTestHostFactory)
98}
99
100func RustTestFactory() android.Module {
101 module, _ := NewRustTest(android.HostAndDeviceSupported)
102 return module.Init()
103}
104
105func RustTestHostFactory() android.Module {
106 module, _ := NewRustTest(android.HostSupported)
107 return module.Init()
108}
109
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700110func (test *testDecorator) testPerSrc() bool {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700111 return true
112}
113
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700114func (test *testDecorator) srcs() []string {
115 return test.binaryDecorator.Properties.Srcs
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700116}
117
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700118func (test *testDecorator) setSrc(name, src string) {
119 test.binaryDecorator.Properties.Srcs = []string{src}
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700120 test.baseCompiler.Properties.Stem = StringPtr(name)
121}
122
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700123func (test *testDecorator) unsetSrc() {
124 test.binaryDecorator.Properties.Srcs = nil
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700125 test.baseCompiler.Properties.Stem = StringPtr("")
126}
127
128type testPerSrc interface {
129 testPerSrc() bool
130 srcs() []string
131 setSrc(string, string)
132 unsetSrc()
133}
134
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700135var _ testPerSrc = (*testDecorator)(nil)
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700136
137func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
138 if m, ok := mctx.Module().(*Module); ok {
139 if test, ok := m.compiler.(testPerSrc); ok {
140 numTests := len(test.srcs())
141 if test.testPerSrc() && numTests > 0 {
142 if duplicate, found := android.CheckDuplicate(test.srcs()); found {
143 mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
144 return
145 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700146 // Rust compiler always compiles one source file at a time and
147 // uses the crate name as output file name.
148 // Cargo uses the test source file name as default crate name,
149 // but that can be redefined.
150 // So when there are multiple source files, the source file names will
151 // be the output file names, but when there is only one test file,
152 // use the crate name.
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700153 testNames := make([]string, numTests)
154 for i, src := range test.srcs() {
155 testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
156 }
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700157 crateName := m.compiler.crateName()
158 if numTests == 1 && crateName != "" {
159 testNames[0] = crateName
160 }
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700161 // TODO(chh): Add an "all tests" variation like cc/test.go?
162 tests := mctx.CreateLocalVariations(testNames...)
163 for i, src := range test.srcs() {
164 tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
165 }
166 }
167 }
168 }
169}