1// 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 "github.com/google/blueprint/proptools" 19 20 "android/soong/android" 21 "android/soong/tradefed" 22) 23 24// Test option struct. 25type TestOptions struct { 26 // If the test is a hostside(no device required) unittest that shall be run during presubmit check. 27 Unit_test *bool 28} 29 30type TestProperties struct { 31 // Disables the creation of a test-specific directory when used with 32 // relative_install_path. Useful if several tests need to be in the same 33 // directory, but test_per_src doesn't work. 34 No_named_install_directory *bool 35 36 // the name of the test configuration (for example "AndroidTest.xml") that should be 37 // installed with the module. 38 Test_config *string `android:"path,arch_variant"` 39 40 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that 41 // should be installed with the module. 42 Test_config_template *string `android:"path,arch_variant"` 43 44 // list of compatibility suites (for example "cts", "vts") that the module should be 45 // installed into. 46 Test_suites []string `android:"arch_variant"` 47 48 // list of files or filegroup modules that provide data that should be installed alongside 49 // the test 50 Data []string `android:"path,arch_variant"` 51 52 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml 53 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true 54 // explicitly. 55 Auto_gen_config *bool 56 57 // if set, build with the standard Rust test harness. Defaults to true. 58 Test_harness *bool 59 60 // Test options. 61 Test_options TestOptions 62} 63 64// A test module is a binary module with extra --test compiler flag 65// and different default installation directory. 66// In golang, inheriance is written as a component. 67type testDecorator struct { 68 *binaryDecorator 69 Properties TestProperties 70 testConfig android.Path 71 72 data []android.DataPath 73} 74 75func (test *testDecorator) dataPaths() []android.DataPath { 76 return test.data 77} 78 79func (test *testDecorator) nativeCoverage() bool { 80 return true 81} 82 83func (test *testDecorator) testHarness() bool { 84 return BoolDefault(test.Properties.Test_harness, true) 85} 86 87func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) { 88 // Build both 32 and 64 targets for device tests. 89 // Cannot build both for host tests yet if the test depends on 90 // something like proc-macro2 that cannot be built for both. 91 multilib := android.MultilibBoth 92 if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported { 93 multilib = android.MultilibFirst 94 } 95 module := newModule(hod, multilib) 96 97 test := &testDecorator{ 98 binaryDecorator: &binaryDecorator{ 99 baseCompiler: NewBaseCompiler("nativetest", "nativetest64", InstallInData), 100 }, 101 } 102 103 module.compiler = test 104 return module, test 105} 106 107func (test *testDecorator) compilerProps() []interface{} { 108 return append(test.binaryDecorator.compilerProps(), &test.Properties) 109} 110 111func (test *testDecorator) install(ctx ModuleContext) { 112 test.testConfig = tradefed.AutoGenRustTestConfig(ctx, 113 test.Properties.Test_config, 114 test.Properties.Test_config_template, 115 test.Properties.Test_suites, 116 nil, 117 test.Properties.Auto_gen_config) 118 119 dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) 120 121 for _, dataSrcPath := range dataSrcPaths { 122 test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath}) 123 } 124 125 // default relative install path is module name 126 if !Bool(test.Properties.No_named_install_directory) { 127 test.baseCompiler.relative = ctx.ModuleName() 128 } else if String(test.baseCompiler.Properties.Relative_install_path) == "" { 129 ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") 130 } 131 132 if ctx.Host() && test.Properties.Test_options.Unit_test == nil { 133 test.Properties.Test_options.Unit_test = proptools.BoolPtr(true) 134 } 135 test.binaryDecorator.install(ctx) 136} 137 138func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { 139 flags = test.binaryDecorator.compilerFlags(ctx, flags) 140 if test.testHarness() { 141 flags.RustFlags = append(flags.RustFlags, "--test") 142 } 143 if ctx.Device() { 144 flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests") 145 } 146 return flags 147} 148 149func (test *testDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { 150 return rlibAutoDep 151} 152 153func init() { 154 // Rust tests are binary files built with --test. 155 android.RegisterModuleType("rust_test", RustTestFactory) 156 android.RegisterModuleType("rust_test_host", RustTestHostFactory) 157} 158 159func RustTestFactory() android.Module { 160 module, _ := NewRustTest(android.HostAndDeviceSupported) 161 return module.Init() 162} 163 164func RustTestHostFactory() android.Module { 165 module, _ := NewRustTest(android.HostSupported) 166 return module.Init() 167} 168 169func (test *testDecorator) stdLinkage(ctx *depsContext) RustLinkage { 170 return RlibLinkage 171} 172 173func (test *testDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { 174 deps = test.binaryDecorator.compilerDeps(ctx, deps) 175 176 deps.Rustlibs = append(deps.Rustlibs, "libtest") 177 178 return deps 179} 180