| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 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 |  | 
|  | 15 | package rust | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "strings" | 
|  | 19 | "testing" | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 20 |  | 
|  | 21 | "android/soong/android" | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 22 | ) | 
|  | 23 |  | 
|  | 24 | // Test that feature flags are being correctly generated. | 
|  | 25 | func TestFeaturesToFlags(t *testing.T) { | 
|  | 26 | ctx := testRust(t, ` | 
|  | 27 | rust_library_host_dylib { | 
|  | 28 | name: "libfoo", | 
|  | 29 | srcs: ["foo.rs"], | 
|  | 30 | crate_name: "foo", | 
|  | 31 | features: [ | 
|  | 32 | "fizz", | 
|  | 33 | "buzz" | 
|  | 34 | ], | 
|  | 35 | }`) | 
|  | 36 |  | 
|  | 37 | libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") | 
|  | 38 |  | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 39 | if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") || | 
|  | 40 | !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") { | 
|  | 41 | t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 42 | } | 
|  | 43 | } | 
|  | 44 |  | 
| Thiébaud Weksteen | c44e737 | 2021-04-07 14:53:06 +0200 | [diff] [blame] | 45 | // Test that cfgs flags are being correctly generated. | 
|  | 46 | func TestCfgsToFlags(t *testing.T) { | 
|  | 47 | ctx := testRust(t, ` | 
|  | 48 | rust_library_host { | 
|  | 49 | name: "libfoo", | 
|  | 50 | srcs: ["foo.rs"], | 
|  | 51 | crate_name: "foo", | 
|  | 52 | cfgs: [ | 
|  | 53 | "std", | 
|  | 54 | "cfg1=\"one\"" | 
|  | 55 | ], | 
|  | 56 | }`) | 
|  | 57 |  | 
|  | 58 | libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") | 
|  | 59 |  | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 60 | if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") || | 
|  | 61 | !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") { | 
|  | 62 | t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) | 
| Thiébaud Weksteen | c44e737 | 2021-04-07 14:53:06 +0200 | [diff] [blame] | 63 | } | 
|  | 64 | } | 
|  | 65 |  | 
| Ivan Lozano | ab58647 | 2024-05-15 10:59:47 -0400 | [diff] [blame] | 66 | func TestLtoFlag(t *testing.T) { | 
|  | 67 | ctx := testRust(t, ` | 
|  | 68 | rust_library_host { | 
|  | 69 | name: "libfoo", | 
|  | 70 | srcs: ["foo.rs"], | 
|  | 71 | crate_name: "foo", | 
|  | 72 | lto: { | 
|  | 73 | thin: false, | 
|  | 74 | } | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | rust_library_host { | 
|  | 78 | name: "libfoo_lto", | 
|  | 79 | srcs: ["foo.rs"], | 
|  | 80 | crate_name: "foo", | 
|  | 81 | } | 
|  | 82 | `) | 
|  | 83 |  | 
|  | 84 | libfoo := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") | 
|  | 85 | libfooLto := ctx.ModuleForTests("libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc") | 
|  | 86 |  | 
|  | 87 | if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") { | 
|  | 88 | t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"]) | 
|  | 89 | } | 
|  | 90 | if !strings.Contains(libfooLto.Args["rustcFlags"], "-C lto=thin") { | 
|  | 91 | t.Fatalf("libfoo expected to enable lto by default -- rustcFlags: %#v", libfooLto.Args["rustcFlags"]) | 
|  | 92 | } | 
|  | 93 | } | 
|  | 94 |  | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 95 | // Test that we reject multiple source files. | 
|  | 96 | func TestEnforceSingleSourceFile(t *testing.T) { | 
|  | 97 |  | 
| Ivan Lozano | 4384568 | 2020-07-09 21:03:28 -0400 | [diff] [blame] | 98 | singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\"" | 
| Matthew Maurer | 1d8e20d | 2023-11-20 21:18:12 +0000 | [diff] [blame] | 99 | prebuiltSingleSrcError := "prebuilt libraries can only have one entry in srcs" | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 100 |  | 
|  | 101 | // Test libraries | 
|  | 102 | testRustError(t, singleSrcError, ` | 
|  | 103 | rust_library_host { | 
|  | 104 | name: "foo-bar-library", | 
|  | 105 | srcs: ["foo.rs", "src/bar.rs"], | 
|  | 106 | }`) | 
|  | 107 |  | 
|  | 108 | // Test binaries | 
|  | 109 | testRustError(t, singleSrcError, ` | 
|  | 110 | rust_binary_host { | 
|  | 111 | name: "foo-bar-binary", | 
|  | 112 | srcs: ["foo.rs", "src/bar.rs"], | 
|  | 113 | }`) | 
|  | 114 |  | 
|  | 115 | // Test proc_macros | 
|  | 116 | testRustError(t, singleSrcError, ` | 
|  | 117 | rust_proc_macro { | 
|  | 118 | name: "foo-bar-proc-macro", | 
|  | 119 | srcs: ["foo.rs", "src/bar.rs"], | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 120 | }`) | 
|  | 121 |  | 
|  | 122 | // Test prebuilts | 
| Matthew Maurer | 1d8e20d | 2023-11-20 21:18:12 +0000 | [diff] [blame] | 123 | testRustError(t, prebuiltSingleSrcError, ` | 
| Ivan Lozano | ffee334 | 2019-08-27 12:03:00 -0700 | [diff] [blame] | 124 | rust_prebuilt_dylib { | 
|  | 125 | name: "foo-bar-prebuilt", | 
|  | 126 | srcs: ["liby.so", "libz.so"], | 
|  | 127 | host_supported: true, | 
|  | 128 | }`) | 
|  | 129 | } | 
| Ivan Lozano | f900f4b | 2020-04-28 13:58:45 -0400 | [diff] [blame] | 130 |  | 
| Seth Moore | 3afac0b | 2021-10-13 15:32:18 -0700 | [diff] [blame] | 131 | // Test that we reject _no_ source files. | 
|  | 132 | func TestEnforceMissingSourceFiles(t *testing.T) { | 
|  | 133 |  | 
|  | 134 | singleSrcError := "srcs must not be empty" | 
|  | 135 |  | 
|  | 136 | // Test libraries | 
|  | 137 | testRustError(t, singleSrcError, ` | 
|  | 138 | rust_library_host { | 
|  | 139 | name: "foo-bar-library", | 
|  | 140 | crate_name: "foo", | 
|  | 141 | }`) | 
|  | 142 |  | 
|  | 143 | // Test binaries | 
|  | 144 | testRustError(t, singleSrcError, ` | 
|  | 145 | rust_binary_host { | 
|  | 146 | name: "foo-bar-binary", | 
|  | 147 | crate_name: "foo", | 
|  | 148 | }`) | 
|  | 149 |  | 
|  | 150 | // Test proc_macros | 
|  | 151 | testRustError(t, singleSrcError, ` | 
|  | 152 | rust_proc_macro { | 
|  | 153 | name: "foo-bar-proc-macro", | 
|  | 154 | crate_name: "foo", | 
|  | 155 | }`) | 
|  | 156 |  | 
|  | 157 | // Test prebuilts | 
|  | 158 | testRustError(t, singleSrcError, ` | 
|  | 159 | rust_prebuilt_dylib { | 
|  | 160 | name: "foo-bar-prebuilt", | 
|  | 161 | crate_name: "foo", | 
|  | 162 | host_supported: true, | 
|  | 163 | }`) | 
|  | 164 | } | 
|  | 165 |  | 
| Ivan Lozano | a9a1fc0 | 2021-08-11 15:13:43 -0400 | [diff] [blame] | 166 | // Test environment vars for Cargo compat are set. | 
|  | 167 | func TestCargoCompat(t *testing.T) { | 
|  | 168 | ctx := testRust(t, ` | 
|  | 169 | rust_binary { | 
|  | 170 | name: "fizz", | 
|  | 171 | srcs: ["foo.rs"], | 
|  | 172 | crate_name: "foo", | 
|  | 173 | cargo_env_compat: true, | 
|  | 174 | cargo_pkg_version: "1.0.0" | 
|  | 175 | }`) | 
|  | 176 |  | 
|  | 177 | fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") | 
|  | 178 |  | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 179 | if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") { | 
|  | 180 | t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"]) | 
| Ivan Lozano | a9a1fc0 | 2021-08-11 15:13:43 -0400 | [diff] [blame] | 181 | } | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 182 | if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") { | 
|  | 183 | t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"]) | 
| Ivan Lozano | a9a1fc0 | 2021-08-11 15:13:43 -0400 | [diff] [blame] | 184 | } | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 185 | if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") { | 
|  | 186 | t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"]) | 
| Ivan Lozano | a9a1fc0 | 2021-08-11 15:13:43 -0400 | [diff] [blame] | 187 | } | 
|  | 188 | } | 
|  | 189 |  | 
| Ivan Lozano | f900f4b | 2020-04-28 13:58:45 -0400 | [diff] [blame] | 190 | func TestInstallDir(t *testing.T) { | 
|  | 191 | ctx := testRust(t, ` | 
|  | 192 | rust_library_dylib { | 
|  | 193 | name: "libfoo", | 
|  | 194 | srcs: ["foo.rs"], | 
|  | 195 | crate_name: "foo", | 
|  | 196 | } | 
|  | 197 | rust_binary { | 
|  | 198 | name: "fizzbuzz", | 
|  | 199 | srcs: ["foo.rs"], | 
|  | 200 | }`) | 
|  | 201 |  | 
|  | 202 | install_path_lib64 := ctx.ModuleForTests("libfoo", | 
|  | 203 | "android_arm64_armv8-a_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() | 
|  | 204 | install_path_lib32 := ctx.ModuleForTests("libfoo", | 
|  | 205 | "android_arm_armv7-a-neon_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() | 
|  | 206 | install_path_bin := ctx.ModuleForTests("fizzbuzz", | 
|  | 207 | "android_arm64_armv8-a").Module().(*Module).compiler.(*binaryDecorator).path.String() | 
|  | 208 |  | 
|  | 209 | if !strings.HasSuffix(install_path_lib64, "system/lib64/libfoo.dylib.so") { | 
|  | 210 | t.Fatalf("unexpected install path for 64-bit library: %#v", install_path_lib64) | 
|  | 211 | } | 
|  | 212 | if !strings.HasSuffix(install_path_lib32, "system/lib/libfoo.dylib.so") { | 
|  | 213 | t.Fatalf("unexpected install path for 32-bit library: %#v", install_path_lib32) | 
|  | 214 | } | 
|  | 215 | if !strings.HasSuffix(install_path_bin, "system/bin/fizzbuzz") { | 
|  | 216 | t.Fatalf("unexpected install path for binary: %#v", install_path_bin) | 
|  | 217 | } | 
|  | 218 | } | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 219 |  | 
|  | 220 | func TestLints(t *testing.T) { | 
|  | 221 |  | 
|  | 222 | bp := ` | 
|  | 223 | // foo uses the default value of lints | 
|  | 224 | rust_library { | 
|  | 225 | name: "libfoo", | 
|  | 226 | srcs: ["foo.rs"], | 
|  | 227 | crate_name: "foo", | 
|  | 228 | } | 
|  | 229 | // bar forces the use of the "android" lint set | 
|  | 230 | rust_library { | 
|  | 231 | name: "libbar", | 
|  | 232 | srcs: ["foo.rs"], | 
|  | 233 | crate_name: "bar", | 
|  | 234 | lints: "android", | 
|  | 235 | } | 
|  | 236 | // foobar explicitly disable all lints | 
|  | 237 | rust_library { | 
|  | 238 | name: "libfoobar", | 
|  | 239 | srcs: ["foo.rs"], | 
|  | 240 | crate_name: "foobar", | 
|  | 241 | lints: "none", | 
|  | 242 | }` | 
|  | 243 |  | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 244 | var lintTests = []struct { | 
|  | 245 | modulePath string | 
|  | 246 | fooFlags   string | 
|  | 247 | }{ | 
|  | 248 | {"", "${config.RustDefaultLints}"}, | 
|  | 249 | {"external/", "${config.RustAllowAllLints}"}, | 
|  | 250 | {"hardware/", "${config.RustVendorLints}"}, | 
|  | 251 | } | 
|  | 252 |  | 
|  | 253 | for _, tc := range lintTests { | 
|  | 254 | t.Run("path="+tc.modulePath, func(t *testing.T) { | 
|  | 255 |  | 
| Paul Duffin | 9e0c3f9 | 2021-03-30 22:45:21 +0100 | [diff] [blame] | 256 | result := android.GroupFixturePreparers( | 
|  | 257 | prepareForRustTest, | 
|  | 258 | // Test with the blueprint file in different directories. | 
|  | 259 | android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), | 
|  | 260 | ).RunTest(t) | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 261 |  | 
| Paul Duffin | 9e0c3f9 | 2021-03-30 22:45:21 +0100 | [diff] [blame] | 262 | r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 263 | android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags) | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 264 |  | 
| Paul Duffin | 9e0c3f9 | 2021-03-30 22:45:21 +0100 | [diff] [blame] | 265 | r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 266 | android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}") | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 267 |  | 
| Paul Duffin | 9e0c3f9 | 2021-03-30 22:45:21 +0100 | [diff] [blame] | 268 | r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") | 
| Wen-yi Chu | 41326c1 | 2023-09-22 03:58:59 +0000 | [diff] [blame] | 269 | android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}") | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 270 | }) | 
|  | 271 | } | 
|  | 272 | } | 
| Ivan Lozano | 042504f | 2020-08-18 14:31:23 -0400 | [diff] [blame] | 273 |  | 
|  | 274 | // Test that devices are linking the stdlib dynamically | 
|  | 275 | func TestStdDeviceLinkage(t *testing.T) { | 
|  | 276 | ctx := testRust(t, ` | 
|  | 277 | rust_binary { | 
|  | 278 | name: "fizz", | 
|  | 279 | srcs: ["foo.rs"], | 
|  | 280 | } | 
|  | 281 | rust_library { | 
|  | 282 | name: "libfoo", | 
|  | 283 | srcs: ["foo.rs"], | 
|  | 284 | crate_name: "foo", | 
|  | 285 | }`) | 
|  | 286 | fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) | 
| Ivan Lozano | 2b08113 | 2020-09-08 12:46:52 -0400 | [diff] [blame] | 287 | fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) | 
| Ivan Lozano | 042504f | 2020-08-18 14:31:23 -0400 | [diff] [blame] | 288 | fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) | 
|  | 289 |  | 
|  | 290 | if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { | 
|  | 291 | t.Errorf("libstd is not linked dynamically for device binaries") | 
|  | 292 | } | 
|  | 293 | if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { | 
|  | 294 | t.Errorf("libstd is not linked dynamically for rlibs") | 
|  | 295 | } | 
|  | 296 | if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { | 
|  | 297 | t.Errorf("libstd is not linked dynamically for dylibs") | 
|  | 298 | } | 
|  | 299 | } | 
| Ivan Lozano | 45a9e31 | 2021-07-27 12:29:12 -0400 | [diff] [blame] | 300 |  | 
|  | 301 | // Ensure that manual link flags are disallowed. | 
|  | 302 | func TestManualLinkageRejection(t *testing.T) { | 
|  | 303 | // rustc flags | 
|  | 304 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 305 | rust_binary { | 
|  | 306 | name: "foo", | 
|  | 307 | srcs: [ | 
|  | 308 | "foo.rs", | 
|  | 309 | ], | 
|  | 310 | flags: ["-lbar"], | 
|  | 311 | } | 
|  | 312 | `) | 
|  | 313 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 314 | rust_binary { | 
|  | 315 | name: "foo", | 
|  | 316 | srcs: [ | 
|  | 317 | "foo.rs", | 
|  | 318 | ], | 
|  | 319 | flags: ["--extern=foo"], | 
|  | 320 | } | 
|  | 321 | `) | 
|  | 322 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 323 | rust_binary { | 
|  | 324 | name: "foo", | 
|  | 325 | srcs: [ | 
|  | 326 | "foo.rs", | 
|  | 327 | ], | 
|  | 328 | flags: ["-Clink-args=foo"], | 
|  | 329 | } | 
|  | 330 | `) | 
|  | 331 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 332 | rust_binary { | 
|  | 333 | name: "foo", | 
|  | 334 | srcs: [ | 
|  | 335 | "foo.rs", | 
|  | 336 | ], | 
|  | 337 | flags: ["-C link-args=foo"], | 
|  | 338 | } | 
|  | 339 | `) | 
|  | 340 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 341 | rust_binary { | 
|  | 342 | name: "foo", | 
|  | 343 | srcs: [ | 
|  | 344 | "foo.rs", | 
|  | 345 | ], | 
|  | 346 | flags: ["-L foo/"], | 
|  | 347 | } | 
|  | 348 | `) | 
|  | 349 |  | 
|  | 350 | // lld flags | 
|  | 351 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 352 | rust_binary { | 
|  | 353 | name: "foo", | 
|  | 354 | srcs: [ | 
|  | 355 | "foo.rs", | 
|  | 356 | ], | 
|  | 357 | ld_flags: ["-Wl,-L bar/"], | 
|  | 358 | } | 
|  | 359 | `) | 
|  | 360 | testRustError(t, ".* cannot be manually specified", ` | 
|  | 361 | rust_binary { | 
|  | 362 | name: "foo", | 
|  | 363 | srcs: [ | 
|  | 364 | "foo.rs", | 
|  | 365 | ], | 
|  | 366 | ld_flags: ["-Wl,-lbar"], | 
|  | 367 | } | 
|  | 368 | `) | 
|  | 369 | } |