| Colin Cross | 41955e8 | 2019-05-29 14:40:35 -0700 | [diff] [blame] | 1 | // Copyright 2015 Google Inc. All rights reserved. | 
|  | 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 android | 
|  | 16 |  | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 17 | import ( | 
| Colin Cross | 14ec66c | 2022-10-03 21:02:27 -0700 | [diff] [blame] | 18 | "github.com/google/blueprint" | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 19 | "path/filepath" | 
|  | 20 | "runtime" | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 21 | "testing" | 
|  | 22 | ) | 
| Colin Cross | 41955e8 | 2019-05-29 14:40:35 -0700 | [diff] [blame] | 23 |  | 
|  | 24 | func TestSrcIsModule(t *testing.T) { | 
|  | 25 | type args struct { | 
|  | 26 | s string | 
|  | 27 | } | 
|  | 28 | tests := []struct { | 
|  | 29 | name       string | 
|  | 30 | args       args | 
|  | 31 | wantModule string | 
|  | 32 | }{ | 
|  | 33 | { | 
|  | 34 | name: "file", | 
|  | 35 | args: args{ | 
|  | 36 | s: "foo", | 
|  | 37 | }, | 
|  | 38 | wantModule: "", | 
|  | 39 | }, | 
|  | 40 | { | 
|  | 41 | name: "module", | 
|  | 42 | args: args{ | 
|  | 43 | s: ":foo", | 
|  | 44 | }, | 
|  | 45 | wantModule: "foo", | 
|  | 46 | }, | 
|  | 47 | { | 
|  | 48 | name: "tag", | 
|  | 49 | args: args{ | 
|  | 50 | s: ":foo{.bar}", | 
|  | 51 | }, | 
|  | 52 | wantModule: "foo{.bar}", | 
|  | 53 | }, | 
|  | 54 | { | 
|  | 55 | name: "extra colon", | 
|  | 56 | args: args{ | 
|  | 57 | s: ":foo:bar", | 
|  | 58 | }, | 
|  | 59 | wantModule: "foo:bar", | 
|  | 60 | }, | 
| Paul Duffin | e6ba072 | 2021-07-12 20:12:12 +0100 | [diff] [blame] | 61 | { | 
|  | 62 | name: "fully qualified", | 
|  | 63 | args: args{ | 
|  | 64 | s: "//foo:bar", | 
|  | 65 | }, | 
|  | 66 | wantModule: "//foo:bar", | 
|  | 67 | }, | 
|  | 68 | { | 
|  | 69 | name: "fully qualified with tag", | 
|  | 70 | args: args{ | 
|  | 71 | s: "//foo:bar{.tag}", | 
|  | 72 | }, | 
|  | 73 | wantModule: "//foo:bar{.tag}", | 
|  | 74 | }, | 
|  | 75 | { | 
|  | 76 | name: "invalid unqualified name", | 
|  | 77 | args: args{ | 
|  | 78 | s: ":foo/bar", | 
|  | 79 | }, | 
|  | 80 | wantModule: "", | 
|  | 81 | }, | 
| Colin Cross | 41955e8 | 2019-05-29 14:40:35 -0700 | [diff] [blame] | 82 | } | 
|  | 83 | for _, tt := range tests { | 
|  | 84 | t.Run(tt.name, func(t *testing.T) { | 
|  | 85 | if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule { | 
|  | 86 | t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule) | 
|  | 87 | } | 
|  | 88 | }) | 
|  | 89 | } | 
|  | 90 | } | 
|  | 91 |  | 
|  | 92 | func TestSrcIsModuleWithTag(t *testing.T) { | 
|  | 93 | type args struct { | 
|  | 94 | s string | 
|  | 95 | } | 
|  | 96 | tests := []struct { | 
|  | 97 | name       string | 
|  | 98 | args       args | 
|  | 99 | wantModule string | 
|  | 100 | wantTag    string | 
|  | 101 | }{ | 
|  | 102 | { | 
|  | 103 | name: "file", | 
|  | 104 | args: args{ | 
|  | 105 | s: "foo", | 
|  | 106 | }, | 
|  | 107 | wantModule: "", | 
|  | 108 | wantTag:    "", | 
|  | 109 | }, | 
|  | 110 | { | 
|  | 111 | name: "module", | 
|  | 112 | args: args{ | 
|  | 113 | s: ":foo", | 
|  | 114 | }, | 
|  | 115 | wantModule: "foo", | 
|  | 116 | wantTag:    "", | 
|  | 117 | }, | 
|  | 118 | { | 
|  | 119 | name: "tag", | 
|  | 120 | args: args{ | 
|  | 121 | s: ":foo{.bar}", | 
|  | 122 | }, | 
|  | 123 | wantModule: "foo", | 
|  | 124 | wantTag:    ".bar", | 
|  | 125 | }, | 
|  | 126 | { | 
|  | 127 | name: "empty tag", | 
|  | 128 | args: args{ | 
|  | 129 | s: ":foo{}", | 
|  | 130 | }, | 
|  | 131 | wantModule: "foo", | 
|  | 132 | wantTag:    "", | 
|  | 133 | }, | 
|  | 134 | { | 
|  | 135 | name: "extra colon", | 
|  | 136 | args: args{ | 
|  | 137 | s: ":foo:bar", | 
|  | 138 | }, | 
|  | 139 | wantModule: "foo:bar", | 
|  | 140 | }, | 
|  | 141 | { | 
|  | 142 | name: "invalid tag", | 
|  | 143 | args: args{ | 
|  | 144 | s: ":foo{.bar", | 
|  | 145 | }, | 
|  | 146 | wantModule: "foo{.bar", | 
|  | 147 | }, | 
|  | 148 | { | 
|  | 149 | name: "invalid tag 2", | 
|  | 150 | args: args{ | 
|  | 151 | s: ":foo.bar}", | 
|  | 152 | }, | 
|  | 153 | wantModule: "foo.bar}", | 
|  | 154 | }, | 
| Paul Duffin | e6ba072 | 2021-07-12 20:12:12 +0100 | [diff] [blame] | 155 | { | 
|  | 156 | name: "fully qualified", | 
|  | 157 | args: args{ | 
|  | 158 | s: "//foo:bar", | 
|  | 159 | }, | 
|  | 160 | wantModule: "//foo:bar", | 
|  | 161 | }, | 
|  | 162 | { | 
|  | 163 | name: "fully qualified with tag", | 
|  | 164 | args: args{ | 
|  | 165 | s: "//foo:bar{.tag}", | 
|  | 166 | }, | 
|  | 167 | wantModule: "//foo:bar", | 
|  | 168 | wantTag:    ".tag", | 
|  | 169 | }, | 
|  | 170 | { | 
|  | 171 | name: "invalid unqualified name", | 
|  | 172 | args: args{ | 
|  | 173 | s: ":foo/bar", | 
|  | 174 | }, | 
|  | 175 | wantModule: "", | 
|  | 176 | }, | 
|  | 177 | { | 
|  | 178 | name: "invalid unqualified name with tag", | 
|  | 179 | args: args{ | 
|  | 180 | s: ":foo/bar{.tag}", | 
|  | 181 | }, | 
|  | 182 | wantModule: "", | 
|  | 183 | }, | 
| Colin Cross | 41955e8 | 2019-05-29 14:40:35 -0700 | [diff] [blame] | 184 | } | 
|  | 185 | for _, tt := range tests { | 
|  | 186 | t.Run(tt.name, func(t *testing.T) { | 
|  | 187 | gotModule, gotTag := SrcIsModuleWithTag(tt.args.s) | 
|  | 188 | if gotModule != tt.wantModule { | 
|  | 189 | t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule) | 
|  | 190 | } | 
|  | 191 | if gotTag != tt.wantTag { | 
|  | 192 | t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag) | 
|  | 193 | } | 
|  | 194 | }) | 
|  | 195 | } | 
|  | 196 | } | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 197 |  | 
|  | 198 | type depsModule struct { | 
|  | 199 | ModuleBase | 
|  | 200 | props struct { | 
|  | 201 | Deps []string | 
|  | 202 | } | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 206 | outputFile := PathForModuleOut(ctx, ctx.ModuleName()) | 
|  | 207 | ctx.Build(pctx, BuildParams{ | 
|  | 208 | Rule:   Touch, | 
|  | 209 | Output: outputFile, | 
|  | 210 | }) | 
|  | 211 | installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile) | 
|  | 212 | ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile) | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 213 | } | 
|  | 214 |  | 
|  | 215 | func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 216 | ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...) | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 217 | } | 
|  | 218 |  | 
|  | 219 | func depsModuleFactory() Module { | 
|  | 220 | m := &depsModule{} | 
|  | 221 | m.AddProperties(&m.props) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 222 | InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon) | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 223 | return m | 
|  | 224 | } | 
|  | 225 |  | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 226 | var prepareForModuleTests = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
|  | 227 | ctx.RegisterModuleType("deps", depsModuleFactory) | 
|  | 228 | }) | 
|  | 229 |  | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 230 | func TestErrorDependsOnDisabledModule(t *testing.T) { | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 231 | bp := ` | 
|  | 232 | deps { | 
|  | 233 | name: "foo", | 
|  | 234 | deps: ["bar"], | 
|  | 235 | } | 
|  | 236 | deps { | 
|  | 237 | name: "bar", | 
|  | 238 | enabled: false, | 
|  | 239 | } | 
|  | 240 | ` | 
|  | 241 |  | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 242 | prepareForModuleTests. | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 243 | ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)). | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 244 | RunTestWithBp(t, bp) | 
| Jooyung Han | d48f3c3 | 2019-08-23 11:18:57 +0900 | [diff] [blame] | 245 | } | 
| Jingwen Chen | ce679d2 | 2020-09-23 04:30:02 +0000 | [diff] [blame] | 246 |  | 
|  | 247 | func TestValidateCorrectBuildParams(t *testing.T) { | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 248 | config := TestConfig(t.TempDir(), nil, "", nil) | 
| Jingwen Chen | ce679d2 | 2020-09-23 04:30:02 +0000 | [diff] [blame] | 249 | pathContext := PathContextForTesting(config) | 
|  | 250 | bparams := convertBuildParams(BuildParams{ | 
|  | 251 | // Test with Output | 
|  | 252 | Output:        PathForOutput(pathContext, "undeclared_symlink"), | 
|  | 253 | SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"), | 
|  | 254 | }) | 
|  | 255 |  | 
|  | 256 | err := validateBuildParams(bparams) | 
|  | 257 | if err != nil { | 
|  | 258 | t.Error(err) | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | bparams = convertBuildParams(BuildParams{ | 
|  | 262 | // Test with ImplicitOutput | 
|  | 263 | ImplicitOutput: PathForOutput(pathContext, "undeclared_symlink"), | 
|  | 264 | SymlinkOutput:  PathForOutput(pathContext, "undeclared_symlink"), | 
|  | 265 | }) | 
|  | 266 |  | 
|  | 267 | err = validateBuildParams(bparams) | 
|  | 268 | if err != nil { | 
|  | 269 | t.Error(err) | 
|  | 270 | } | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | func TestValidateIncorrectBuildParams(t *testing.T) { | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 274 | config := TestConfig(t.TempDir(), nil, "", nil) | 
| Jingwen Chen | ce679d2 | 2020-09-23 04:30:02 +0000 | [diff] [blame] | 275 | pathContext := PathContextForTesting(config) | 
|  | 276 | params := BuildParams{ | 
|  | 277 | Output:          PathForOutput(pathContext, "regular_output"), | 
|  | 278 | Outputs:         PathsForOutput(pathContext, []string{"out1", "out2"}), | 
|  | 279 | ImplicitOutput:  PathForOutput(pathContext, "implicit_output"), | 
|  | 280 | ImplicitOutputs: PathsForOutput(pathContext, []string{"i_out1", "_out2"}), | 
|  | 281 | SymlinkOutput:   PathForOutput(pathContext, "undeclared_symlink"), | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | bparams := convertBuildParams(params) | 
|  | 285 | err := validateBuildParams(bparams) | 
|  | 286 | if err != nil { | 
|  | 287 | FailIfNoMatchingErrors(t, "undeclared_symlink is not a declared output or implicit output", []error{err}) | 
|  | 288 | } else { | 
|  | 289 | t.Errorf("Expected build params to fail validation: %+v", bparams) | 
|  | 290 | } | 
|  | 291 | } | 
| Paul Duffin | 89968e3 | 2020-11-23 18:17:03 +0000 | [diff] [blame] | 292 |  | 
|  | 293 | func TestDistErrorChecking(t *testing.T) { | 
|  | 294 | bp := ` | 
|  | 295 | deps { | 
|  | 296 | name: "foo", | 
|  | 297 | dist: { | 
|  | 298 | dest: "../invalid-dest", | 
|  | 299 | dir: "../invalid-dir", | 
|  | 300 | suffix: "invalid/suffix", | 
|  | 301 | }, | 
|  | 302 | dists: [ | 
|  | 303 | { | 
|  | 304 | dest: "../invalid-dest0", | 
|  | 305 | dir: "../invalid-dir0", | 
|  | 306 | suffix: "invalid/suffix0", | 
|  | 307 | }, | 
|  | 308 | { | 
|  | 309 | dest: "../invalid-dest1", | 
|  | 310 | dir: "../invalid-dir1", | 
|  | 311 | suffix: "invalid/suffix1", | 
|  | 312 | }, | 
|  | 313 | ], | 
|  | 314 | } | 
|  | 315 | ` | 
|  | 316 |  | 
| Paul Duffin | 89968e3 | 2020-11-23 18:17:03 +0000 | [diff] [blame] | 317 | expectedErrs := []string{ | 
|  | 318 | "\\QAndroid.bp:5:13: module \"foo\": dist.dest: Path is outside directory: ../invalid-dest\\E", | 
|  | 319 | "\\QAndroid.bp:6:12: module \"foo\": dist.dir: Path is outside directory: ../invalid-dir\\E", | 
|  | 320 | "\\QAndroid.bp:7:15: module \"foo\": dist.suffix: Suffix may not contain a '/' character.\\E", | 
|  | 321 | "\\QAndroid.bp:11:15: module \"foo\": dists[0].dest: Path is outside directory: ../invalid-dest0\\E", | 
|  | 322 | "\\QAndroid.bp:12:14: module \"foo\": dists[0].dir: Path is outside directory: ../invalid-dir0\\E", | 
|  | 323 | "\\QAndroid.bp:13:17: module \"foo\": dists[0].suffix: Suffix may not contain a '/' character.\\E", | 
|  | 324 | "\\QAndroid.bp:16:15: module \"foo\": dists[1].dest: Path is outside directory: ../invalid-dest1\\E", | 
|  | 325 | "\\QAndroid.bp:17:14: module \"foo\": dists[1].dir: Path is outside directory: ../invalid-dir1\\E", | 
|  | 326 | "\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E", | 
|  | 327 | } | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 328 |  | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 329 | prepareForModuleTests. | 
| Paul Duffin | f62dc9b | 2021-03-16 19:44:51 +0000 | [diff] [blame] | 330 | ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)). | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 331 | RunTestWithBp(t, bp) | 
| Paul Duffin | 89968e3 | 2020-11-23 18:17:03 +0000 | [diff] [blame] | 332 | } | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 333 |  | 
|  | 334 | func TestInstall(t *testing.T) { | 
|  | 335 | if runtime.GOOS != "linux" { | 
|  | 336 | t.Skip("requires linux") | 
|  | 337 | } | 
|  | 338 | bp := ` | 
|  | 339 | deps { | 
|  | 340 | name: "foo", | 
|  | 341 | deps: ["bar"], | 
|  | 342 | } | 
|  | 343 |  | 
|  | 344 | deps { | 
|  | 345 | name: "bar", | 
|  | 346 | deps: ["baz", "qux"], | 
|  | 347 | } | 
|  | 348 |  | 
|  | 349 | deps { | 
|  | 350 | name: "baz", | 
|  | 351 | deps: ["qux"], | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 | deps { | 
|  | 355 | name: "qux", | 
|  | 356 | } | 
|  | 357 | ` | 
|  | 358 |  | 
|  | 359 | result := GroupFixturePreparers( | 
|  | 360 | prepareForModuleTests, | 
|  | 361 | PrepareForTestWithArchMutator, | 
|  | 362 | ).RunTestWithBp(t, bp) | 
|  | 363 |  | 
|  | 364 | module := func(name string, host bool) TestingModule { | 
|  | 365 | variant := "android_common" | 
|  | 366 | if host { | 
|  | 367 | variant = result.Config.BuildOSCommonTarget.String() | 
|  | 368 | } | 
|  | 369 | return result.ModuleForTests(name, variant) | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } | 
|  | 373 |  | 
|  | 374 | installRule := func(name string) TestingBuildParams { | 
|  | 375 | return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name)) | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | symlinkRule := func(name string) TestingBuildParams { | 
|  | 379 | return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name)) | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } | 
|  | 383 |  | 
|  | 384 | hostInstallRule := func(name string) TestingBuildParams { | 
|  | 385 | return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name)) | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | hostSymlinkRule := func(name string) TestingBuildParams { | 
|  | 389 | return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name)) | 
|  | 390 | } | 
|  | 391 |  | 
|  | 392 | assertInputs := func(params TestingBuildParams, inputs ...Path) { | 
|  | 393 | t.Helper() | 
|  | 394 | AssertArrayString(t, "expected inputs", Paths(inputs).Strings(), | 
|  | 395 | append(PathsIfNonNil(params.Input), params.Inputs...).Strings()) | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | assertImplicits := func(params TestingBuildParams, implicits ...Path) { | 
|  | 399 | t.Helper() | 
|  | 400 | AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(), | 
|  | 401 | append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings()) | 
|  | 402 | } | 
|  | 403 |  | 
|  | 404 | assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) { | 
|  | 405 | t.Helper() | 
|  | 406 | AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(), | 
|  | 407 | params.OrderOnly.Strings()) | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | // Check host install rule dependencies | 
|  | 411 | assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output) | 
|  | 412 | assertImplicits(hostInstallRule("foo"), | 
|  | 413 | hostInstallRule("bar").Output, | 
|  | 414 | hostSymlinkRule("bar").Output, | 
|  | 415 | hostInstallRule("baz").Output, | 
|  | 416 | hostSymlinkRule("baz").Output, | 
|  | 417 | hostInstallRule("qux").Output, | 
|  | 418 | hostSymlinkRule("qux").Output, | 
|  | 419 | ) | 
|  | 420 | assertOrderOnlys(hostInstallRule("foo")) | 
|  | 421 |  | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 422 | // Check host symlink rule dependencies.  Host symlinks must use a normal dependency, not an | 
|  | 423 | // order-only dependency, so that the tool gets updated when the symlink is depended on. | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 424 | assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output) | 
|  | 425 | assertImplicits(hostSymlinkRule("foo")) | 
|  | 426 | assertOrderOnlys(hostSymlinkRule("foo")) | 
|  | 427 |  | 
|  | 428 | // Check device install rule dependencies | 
|  | 429 | assertInputs(installRule("foo"), outputRule("foo").Output) | 
|  | 430 | assertImplicits(installRule("foo")) | 
|  | 431 | assertOrderOnlys(installRule("foo"), | 
|  | 432 | installRule("bar").Output, | 
|  | 433 | symlinkRule("bar").Output, | 
|  | 434 | installRule("baz").Output, | 
|  | 435 | symlinkRule("baz").Output, | 
|  | 436 | installRule("qux").Output, | 
|  | 437 | symlinkRule("qux").Output, | 
|  | 438 | ) | 
|  | 439 |  | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 440 | // Check device symlink rule dependencies.  Device symlinks could use an order-only dependency, | 
|  | 441 | // but the current implementation uses a normal dependency. | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 442 | assertInputs(symlinkRule("foo"), installRule("foo").Output) | 
|  | 443 | assertImplicits(symlinkRule("foo")) | 
|  | 444 | assertOrderOnlys(symlinkRule("foo")) | 
|  | 445 | } | 
|  | 446 |  | 
| Colin Cross | c68db4b | 2021-11-11 18:59:15 -0800 | [diff] [blame] | 447 | func TestInstallKatiEnabled(t *testing.T) { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 448 | if runtime.GOOS != "linux" { | 
|  | 449 | t.Skip("requires linux") | 
|  | 450 | } | 
|  | 451 | bp := ` | 
|  | 452 | deps { | 
|  | 453 | name: "foo", | 
|  | 454 | deps: ["bar"], | 
|  | 455 | } | 
|  | 456 |  | 
|  | 457 | deps { | 
|  | 458 | name: "bar", | 
|  | 459 | deps: ["baz", "qux"], | 
|  | 460 | } | 
|  | 461 |  | 
|  | 462 | deps { | 
|  | 463 | name: "baz", | 
|  | 464 | deps: ["qux"], | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | deps { | 
|  | 468 | name: "qux", | 
|  | 469 | } | 
|  | 470 | ` | 
|  | 471 |  | 
|  | 472 | result := GroupFixturePreparers( | 
|  | 473 | prepareForModuleTests, | 
|  | 474 | PrepareForTestWithArchMutator, | 
|  | 475 | FixtureModifyConfig(SetKatiEnabledForTests), | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 476 | PrepareForTestWithMakevars, | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 477 | ).RunTestWithBp(t, bp) | 
|  | 478 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 479 | rules := result.InstallMakeRulesForTesting(t) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 480 |  | 
|  | 481 | module := func(name string, host bool) TestingModule { | 
|  | 482 | variant := "android_common" | 
|  | 483 | if host { | 
|  | 484 | variant = result.Config.BuildOSCommonTarget.String() | 
|  | 485 | } | 
|  | 486 | return result.ModuleForTests(name, variant) | 
|  | 487 | } | 
|  | 488 |  | 
|  | 489 | outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } | 
|  | 490 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 491 | ruleForOutput := func(output string) InstallMakeRule { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 492 | for _, rule := range rules { | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 493 | if rule.Target == output { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 494 | return rule | 
|  | 495 | } | 
|  | 496 | } | 
|  | 497 | t.Fatalf("no make install rule for %s", output) | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 498 | return InstallMakeRule{} | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 499 | } | 
|  | 500 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 501 | installRule := func(name string) InstallMakeRule { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 502 | return ruleForOutput(filepath.Join("out/target/product/test_device/system", name)) | 
|  | 503 | } | 
|  | 504 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 505 | symlinkRule := func(name string) InstallMakeRule { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 506 | return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name)) | 
|  | 507 | } | 
|  | 508 |  | 
|  | 509 | hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } | 
|  | 510 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 511 | hostInstallRule := func(name string) InstallMakeRule { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 512 | return ruleForOutput(filepath.Join("out/host/linux-x86", name)) | 
|  | 513 | } | 
|  | 514 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 515 | hostSymlinkRule := func(name string) InstallMakeRule { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 516 | return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name)) | 
|  | 517 | } | 
|  | 518 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 519 | assertDeps := func(rule InstallMakeRule, deps ...string) { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 520 | t.Helper() | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 521 | AssertArrayString(t, "expected inputs", deps, rule.Deps) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 522 | } | 
|  | 523 |  | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 524 | assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) { | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 525 | t.Helper() | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 526 | AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 527 | } | 
|  | 528 |  | 
|  | 529 | // Check host install rule dependencies | 
|  | 530 | assertDeps(hostInstallRule("foo"), | 
|  | 531 | hostOutputRule("foo").Output.String(), | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 532 | hostInstallRule("bar").Target, | 
|  | 533 | hostSymlinkRule("bar").Target, | 
|  | 534 | hostInstallRule("baz").Target, | 
|  | 535 | hostSymlinkRule("baz").Target, | 
|  | 536 | hostInstallRule("qux").Target, | 
|  | 537 | hostSymlinkRule("qux").Target, | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 538 | ) | 
|  | 539 | assertOrderOnlys(hostInstallRule("foo")) | 
|  | 540 |  | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 541 | // Check host symlink rule dependencies.  Host symlinks must use a normal dependency, not an | 
|  | 542 | // order-only dependency, so that the tool gets updated when the symlink is depended on. | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 543 | assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target) | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 544 | assertOrderOnlys(hostSymlinkRule("foo")) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 545 |  | 
|  | 546 | // Check device install rule dependencies | 
|  | 547 | assertDeps(installRule("foo"), outputRule("foo").Output.String()) | 
|  | 548 | assertOrderOnlys(installRule("foo"), | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 549 | installRule("bar").Target, | 
|  | 550 | symlinkRule("bar").Target, | 
|  | 551 | installRule("baz").Target, | 
|  | 552 | symlinkRule("baz").Target, | 
|  | 553 | installRule("qux").Target, | 
|  | 554 | symlinkRule("qux").Target, | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 555 | ) | 
|  | 556 |  | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 557 | // Check device symlink rule dependencies.  Device symlinks could use an order-only dependency, | 
|  | 558 | // but the current implementation uses a normal dependency. | 
| Martin Stjernholm | 1ebef5b | 2022-02-10 23:34:28 +0000 | [diff] [blame] | 559 | assertDeps(symlinkRule("foo"), installRule("foo").Target) | 
| Colin Cross | 64002af | 2021-11-09 16:37:52 -0800 | [diff] [blame] | 560 | assertOrderOnlys(symlinkRule("foo")) | 
| Colin Cross | 6ac9576 | 2021-11-09 13:17:44 -0800 | [diff] [blame] | 561 | } | 
|  | 562 |  | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 563 | type PropsTestModuleEmbedded struct { | 
|  | 564 | Embedded_prop *string | 
|  | 565 | } | 
|  | 566 |  | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 567 | type StructInSlice struct { | 
|  | 568 | G string | 
|  | 569 | H bool | 
|  | 570 | I []string | 
|  | 571 | } | 
|  | 572 |  | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 573 | type propsTestModule struct { | 
|  | 574 | ModuleBase | 
|  | 575 | DefaultableModuleBase | 
|  | 576 | props struct { | 
|  | 577 | A string `android:"arch_variant"` | 
|  | 578 | B *bool | 
|  | 579 | C []string | 
|  | 580 | } | 
|  | 581 | otherProps struct { | 
|  | 582 | PropsTestModuleEmbedded | 
|  | 583 |  | 
|  | 584 | D      *int64 | 
|  | 585 | Nested struct { | 
|  | 586 | E *string | 
|  | 587 | } | 
|  | 588 | F *string `blueprint:"mutated"` | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 589 |  | 
|  | 590 | Slice_of_struct []StructInSlice | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 591 | } | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | func propsTestModuleFactory() Module { | 
|  | 595 | module := &propsTestModule{} | 
|  | 596 | module.AddProperties(&module.props, &module.otherProps) | 
|  | 597 | InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth) | 
|  | 598 | InitDefaultableModule(module) | 
|  | 599 | return module | 
|  | 600 | } | 
|  | 601 |  | 
|  | 602 | type propsTestModuleDefaults struct { | 
|  | 603 | ModuleBase | 
|  | 604 | DefaultsModuleBase | 
|  | 605 | } | 
|  | 606 |  | 
|  | 607 | func propsTestModuleDefaultsFactory() Module { | 
|  | 608 | defaults := &propsTestModuleDefaults{} | 
|  | 609 | module := propsTestModule{} | 
|  | 610 | defaults.AddProperties(&module.props, &module.otherProps) | 
|  | 611 | InitDefaultsModule(defaults) | 
|  | 612 | return defaults | 
|  | 613 | } | 
|  | 614 |  | 
|  | 615 | func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
|  | 616 | str := "abc" | 
|  | 617 | p.otherProps.F = &str | 
|  | 618 | } | 
|  | 619 |  | 
|  | 620 | func TestUsedProperties(t *testing.T) { | 
|  | 621 | testCases := []struct { | 
|  | 622 | desc          string | 
|  | 623 | bp            string | 
|  | 624 | expectedProps []propInfo | 
|  | 625 | }{ | 
|  | 626 | { | 
|  | 627 | desc: "only name", | 
|  | 628 | bp: `test { | 
|  | 629 | name: "foo", | 
|  | 630 | } | 
|  | 631 | `, | 
|  | 632 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 633 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 634 | }, | 
|  | 635 | }, | 
|  | 636 | { | 
|  | 637 | desc: "some props", | 
|  | 638 | bp: `test { | 
|  | 639 | name: "foo", | 
|  | 640 | a: "abc", | 
|  | 641 | b: true, | 
|  | 642 | d: 123, | 
|  | 643 | } | 
|  | 644 | `, | 
|  | 645 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 646 | propInfo{Name: "A", Type: "string", Value: "abc"}, | 
|  | 647 | propInfo{Name: "B", Type: "bool", Value: "true"}, | 
|  | 648 | propInfo{Name: "D", Type: "int64", Value: "123"}, | 
|  | 649 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 650 | }, | 
|  | 651 | }, | 
|  | 652 | { | 
|  | 653 | desc: "unused non-pointer prop", | 
|  | 654 | bp: `test { | 
|  | 655 | name: "foo", | 
|  | 656 | b: true, | 
|  | 657 | d: 123, | 
|  | 658 | } | 
|  | 659 | `, | 
|  | 660 | expectedProps: []propInfo{ | 
|  | 661 | // for non-pointer cannot distinguish between unused and intentionally set to empty | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 662 | propInfo{Name: "A", Type: "string", Value: ""}, | 
|  | 663 | propInfo{Name: "B", Type: "bool", Value: "true"}, | 
|  | 664 | propInfo{Name: "D", Type: "int64", Value: "123"}, | 
|  | 665 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 666 | }, | 
|  | 667 | }, | 
|  | 668 | { | 
|  | 669 | desc: "nested props", | 
|  | 670 | bp: `test { | 
|  | 671 | name: "foo", | 
|  | 672 | nested: { | 
|  | 673 | e: "abc", | 
|  | 674 | } | 
|  | 675 | } | 
|  | 676 | `, | 
|  | 677 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 678 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
|  | 679 | propInfo{Name: "Nested.E", Type: "string", Value: "abc"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 680 | }, | 
|  | 681 | }, | 
|  | 682 | { | 
|  | 683 | desc: "arch props", | 
|  | 684 | bp: `test { | 
|  | 685 | name: "foo", | 
|  | 686 | arch: { | 
|  | 687 | x86_64: { | 
|  | 688 | a: "abc", | 
|  | 689 | }, | 
|  | 690 | } | 
|  | 691 | } | 
|  | 692 | `, | 
|  | 693 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 694 | propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"}, | 
|  | 695 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 696 | }, | 
|  | 697 | }, | 
|  | 698 | { | 
|  | 699 | desc: "embedded props", | 
|  | 700 | bp: `test { | 
|  | 701 | name: "foo", | 
|  | 702 | embedded_prop: "a", | 
|  | 703 | } | 
|  | 704 | `, | 
|  | 705 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 706 | propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, | 
|  | 707 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
|  | 708 | }, | 
|  | 709 | }, | 
|  | 710 | { | 
|  | 711 | desc: "struct slice", | 
|  | 712 | bp: `test { | 
|  | 713 | name: "foo", | 
|  | 714 | slice_of_struct: [ | 
|  | 715 | { | 
|  | 716 | g: "abc", | 
|  | 717 | h: false, | 
|  | 718 | i: ["baz"], | 
|  | 719 | }, | 
|  | 720 | { | 
|  | 721 | g: "def", | 
|  | 722 | h: true, | 
|  | 723 | i: [], | 
|  | 724 | }, | 
|  | 725 | ] | 
|  | 726 | } | 
|  | 727 | `, | 
|  | 728 | expectedProps: []propInfo{ | 
|  | 729 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
|  | 730 | propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{ | 
|  | 731 | `android.StructInSlice{G: abc, H: false, I: [baz]}`, | 
|  | 732 | `android.StructInSlice{G: def, H: true, I: []}`, | 
|  | 733 | }}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 734 | }, | 
|  | 735 | }, | 
|  | 736 | { | 
|  | 737 | desc: "defaults", | 
|  | 738 | bp: ` | 
|  | 739 | test_defaults { | 
|  | 740 | name: "foo_defaults", | 
|  | 741 | a: "a", | 
|  | 742 | b: true, | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 743 | c: ["default_c"], | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 744 | embedded_prop:"a", | 
|  | 745 | arch: { | 
|  | 746 | x86_64: { | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 747 | a: "x86_64 a", | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 748 | }, | 
|  | 749 | }, | 
|  | 750 | } | 
|  | 751 | test { | 
|  | 752 | name: "foo", | 
|  | 753 | defaults: ["foo_defaults"], | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 754 | c: ["c"], | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 755 | nested: { | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 756 | e: "nested e", | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 757 | }, | 
|  | 758 | target: { | 
|  | 759 | linux: { | 
|  | 760 | a: "a", | 
|  | 761 | }, | 
|  | 762 | }, | 
|  | 763 | } | 
|  | 764 | `, | 
|  | 765 | expectedProps: []propInfo{ | 
| Liz Kammer | 898e076 | 2022-03-22 11:27:26 -0400 | [diff] [blame] | 766 | propInfo{Name: "A", Type: "string", Value: "a"}, | 
|  | 767 | propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"}, | 
|  | 768 | propInfo{Name: "B", Type: "bool", Value: "true"}, | 
|  | 769 | propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}}, | 
|  | 770 | propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}}, | 
|  | 771 | propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, | 
|  | 772 | propInfo{Name: "Name", Type: "string", Value: "foo"}, | 
|  | 773 | propInfo{Name: "Nested.E", Type: "string", Value: "nested e"}, | 
|  | 774 | propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"}, | 
| Liz Kammer | 9525e71 | 2022-01-05 13:46:24 -0500 | [diff] [blame] | 775 | }, | 
|  | 776 | }, | 
|  | 777 | } | 
|  | 778 |  | 
|  | 779 | for _, tc := range testCases { | 
|  | 780 | t.Run(tc.desc, func(t *testing.T) { | 
|  | 781 | result := GroupFixturePreparers( | 
|  | 782 | PrepareForTestWithAllowMissingDependencies, | 
|  | 783 | PrepareForTestWithDefaults, | 
|  | 784 | FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
|  | 785 | ctx.RegisterModuleType("test", propsTestModuleFactory) | 
|  | 786 | ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory) | 
|  | 787 | }), | 
|  | 788 | FixtureWithRootAndroidBp(tc.bp), | 
|  | 789 | ).RunTest(t) | 
|  | 790 |  | 
|  | 791 | foo := result.ModuleForTests("foo", "").Module().base() | 
|  | 792 |  | 
|  | 793 | AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues()) | 
|  | 794 |  | 
|  | 795 | }) | 
|  | 796 | } | 
|  | 797 | } | 
| Bob Badour | 4101c71 | 2022-02-09 11:54:35 -0800 | [diff] [blame] | 798 |  | 
|  | 799 | func TestSortedUniqueNamedPaths(t *testing.T) { | 
|  | 800 | type np struct { | 
|  | 801 | path, name string | 
|  | 802 | } | 
|  | 803 | makePaths := func(l []np) NamedPaths { | 
|  | 804 | result := make(NamedPaths, 0, len(l)) | 
|  | 805 | for _, p := range l { | 
|  | 806 | result = append(result, NamedPath{PathForTesting(p.path), p.name}) | 
|  | 807 | } | 
|  | 808 | return result | 
|  | 809 | } | 
|  | 810 |  | 
|  | 811 | tests := []struct { | 
|  | 812 | name        string | 
|  | 813 | in          []np | 
|  | 814 | expectedOut []np | 
|  | 815 | }{ | 
|  | 816 | { | 
|  | 817 | name:        "empty", | 
|  | 818 | in:          []np{}, | 
|  | 819 | expectedOut: []np{}, | 
|  | 820 | }, | 
|  | 821 | { | 
|  | 822 | name: "all_same", | 
|  | 823 | in: []np{ | 
|  | 824 | {"a.txt", "A"}, | 
|  | 825 | {"a.txt", "A"}, | 
|  | 826 | {"a.txt", "A"}, | 
|  | 827 | {"a.txt", "A"}, | 
|  | 828 | {"a.txt", "A"}, | 
|  | 829 | }, | 
|  | 830 | expectedOut: []np{ | 
|  | 831 | {"a.txt", "A"}, | 
|  | 832 | }, | 
|  | 833 | }, | 
|  | 834 | { | 
|  | 835 | name: "same_path_different_names", | 
|  | 836 | in: []np{ | 
|  | 837 | {"a.txt", "C"}, | 
|  | 838 | {"a.txt", "A"}, | 
|  | 839 | {"a.txt", "D"}, | 
|  | 840 | {"a.txt", "B"}, | 
|  | 841 | {"a.txt", "E"}, | 
|  | 842 | }, | 
|  | 843 | expectedOut: []np{ | 
|  | 844 | {"a.txt", "A"}, | 
|  | 845 | {"a.txt", "B"}, | 
|  | 846 | {"a.txt", "C"}, | 
|  | 847 | {"a.txt", "D"}, | 
|  | 848 | {"a.txt", "E"}, | 
|  | 849 | }, | 
|  | 850 | }, | 
|  | 851 | { | 
|  | 852 | name: "different_paths_same_name", | 
|  | 853 | in: []np{ | 
|  | 854 | {"b/b.txt", "A"}, | 
|  | 855 | {"a/a.txt", "A"}, | 
|  | 856 | {"a/txt", "A"}, | 
|  | 857 | {"b", "A"}, | 
|  | 858 | {"a/b/d", "A"}, | 
|  | 859 | }, | 
|  | 860 | expectedOut: []np{ | 
|  | 861 | {"a/a.txt", "A"}, | 
|  | 862 | {"a/b/d", "A"}, | 
|  | 863 | {"a/txt", "A"}, | 
|  | 864 | {"b/b.txt", "A"}, | 
|  | 865 | {"b", "A"}, | 
|  | 866 | }, | 
|  | 867 | }, | 
|  | 868 | { | 
|  | 869 | name: "all_different", | 
|  | 870 | in: []np{ | 
|  | 871 | {"b/b.txt", "A"}, | 
|  | 872 | {"a/a.txt", "B"}, | 
|  | 873 | {"a/txt", "D"}, | 
|  | 874 | {"b", "C"}, | 
|  | 875 | {"a/b/d", "E"}, | 
|  | 876 | }, | 
|  | 877 | expectedOut: []np{ | 
|  | 878 | {"a/a.txt", "B"}, | 
|  | 879 | {"a/b/d", "E"}, | 
|  | 880 | {"a/txt", "D"}, | 
|  | 881 | {"b/b.txt", "A"}, | 
|  | 882 | {"b", "C"}, | 
|  | 883 | }, | 
|  | 884 | }, | 
|  | 885 | { | 
|  | 886 | name: "some_different", | 
|  | 887 | in: []np{ | 
|  | 888 | {"b/b.txt", "A"}, | 
|  | 889 | {"a/a.txt", "B"}, | 
|  | 890 | {"a/txt", "D"}, | 
|  | 891 | {"a/b/d", "E"}, | 
|  | 892 | {"b", "C"}, | 
|  | 893 | {"a/a.txt", "B"}, | 
|  | 894 | {"a/b/d", "E"}, | 
|  | 895 | }, | 
|  | 896 | expectedOut: []np{ | 
|  | 897 | {"a/a.txt", "B"}, | 
|  | 898 | {"a/b/d", "E"}, | 
|  | 899 | {"a/txt", "D"}, | 
|  | 900 | {"b/b.txt", "A"}, | 
|  | 901 | {"b", "C"}, | 
|  | 902 | }, | 
|  | 903 | }, | 
|  | 904 | } | 
|  | 905 | for _, tt := range tests { | 
|  | 906 | t.Run(tt.name, func(t *testing.T) { | 
|  | 907 | actual := SortedUniqueNamedPaths(makePaths(tt.in)) | 
|  | 908 | expected := makePaths(tt.expectedOut) | 
|  | 909 | t.Logf("actual: %v", actual) | 
|  | 910 | t.Logf("expected: %v", expected) | 
|  | 911 | AssertDeepEquals(t, "SortedUniqueNamedPaths ", expected, actual) | 
|  | 912 | }) | 
|  | 913 | } | 
|  | 914 | } | 
| Zhenhuang Wang | 0ac5a43 | 2022-08-12 18:49:20 +0800 | [diff] [blame] | 915 |  | 
| Zhenhuang Wang | 409d277 | 2022-08-22 16:00:05 +0800 | [diff] [blame] | 916 | func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { | 
| Zhenhuang Wang | 0ac5a43 | 2022-08-12 18:49:20 +0800 | [diff] [blame] | 917 | tests := []struct { | 
|  | 918 | name        string | 
|  | 919 | testOptions CommonTestOptions | 
|  | 920 | expected    map[string][]string | 
|  | 921 | }{ | 
|  | 922 | { | 
|  | 923 | name:        "empty", | 
|  | 924 | testOptions: CommonTestOptions{}, | 
|  | 925 | expected:    map[string][]string{}, | 
|  | 926 | }, | 
|  | 927 | { | 
|  | 928 | name: "is unit test", | 
|  | 929 | testOptions: CommonTestOptions{ | 
|  | 930 | Unit_test: boolPtr(true), | 
|  | 931 | }, | 
|  | 932 | expected: map[string][]string{ | 
|  | 933 | "LOCAL_IS_UNIT_TEST": []string{"true"}, | 
|  | 934 | }, | 
|  | 935 | }, | 
|  | 936 | { | 
|  | 937 | name: "is not unit test", | 
|  | 938 | testOptions: CommonTestOptions{ | 
|  | 939 | Unit_test: boolPtr(false), | 
|  | 940 | }, | 
|  | 941 | expected: map[string][]string{}, | 
|  | 942 | }, | 
| Zhenhuang Wang | 409d277 | 2022-08-22 16:00:05 +0800 | [diff] [blame] | 943 | { | 
|  | 944 | name: "empty tag", | 
|  | 945 | testOptions: CommonTestOptions{ | 
|  | 946 | Tags: []string{}, | 
|  | 947 | }, | 
|  | 948 | expected: map[string][]string{}, | 
|  | 949 | }, | 
|  | 950 | { | 
|  | 951 | name: "single tag", | 
|  | 952 | testOptions: CommonTestOptions{ | 
|  | 953 | Tags: []string{"tag1"}, | 
|  | 954 | }, | 
|  | 955 | expected: map[string][]string{ | 
|  | 956 | "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"}, | 
|  | 957 | }, | 
|  | 958 | }, | 
|  | 959 | { | 
|  | 960 | name: "multiple tag", | 
|  | 961 | testOptions: CommonTestOptions{ | 
|  | 962 | Tags: []string{"tag1", "tag2", "tag3"}, | 
|  | 963 | }, | 
|  | 964 | expected: map[string][]string{ | 
|  | 965 | "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"}, | 
|  | 966 | }, | 
|  | 967 | }, | 
| Zhenhuang Wang | 0ac5a43 | 2022-08-12 18:49:20 +0800 | [diff] [blame] | 968 | } | 
|  | 969 | for _, tt := range tests { | 
|  | 970 | t.Run(tt.name, func(t *testing.T) { | 
|  | 971 | actualEntries := AndroidMkEntries{ | 
|  | 972 | EntryMap: map[string][]string{}, | 
|  | 973 | } | 
|  | 974 | tt.testOptions.SetAndroidMkEntries(&actualEntries) | 
|  | 975 | actual := actualEntries.EntryMap | 
|  | 976 | t.Logf("actual: %v", actual) | 
|  | 977 | t.Logf("expected: %v", tt.expected) | 
|  | 978 | AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual) | 
|  | 979 | }) | 
|  | 980 | } | 
|  | 981 | } | 
| Colin Cross | 14ec66c | 2022-10-03 21:02:27 -0700 | [diff] [blame] | 982 |  | 
|  | 983 | type fakeBlueprintModule struct{} | 
|  | 984 |  | 
|  | 985 | func (fakeBlueprintModule) Name() string { return "foo" } | 
|  | 986 |  | 
|  | 987 | func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} | 
|  | 988 |  | 
|  | 989 | type sourceProducerTestModule struct { | 
|  | 990 | fakeBlueprintModule | 
|  | 991 | source Path | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } | 
|  | 995 |  | 
|  | 996 | type outputFileProducerTestModule struct { | 
|  | 997 | fakeBlueprintModule | 
|  | 998 | output map[string]Path | 
|  | 999 | error  map[string]error | 
|  | 1000 | } | 
|  | 1001 |  | 
|  | 1002 | func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { | 
|  | 1003 | return PathsIfNonNil(o.output[tag]), o.error[tag] | 
|  | 1004 | } | 
|  | 1005 |  | 
|  | 1006 | type pathContextAddMissingDependenciesWrapper struct { | 
|  | 1007 | PathContext | 
|  | 1008 | missingDeps []string | 
|  | 1009 | } | 
|  | 1010 |  | 
|  | 1011 | func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { | 
|  | 1012 | p.missingDeps = append(p.missingDeps, deps...) | 
|  | 1013 | } | 
|  | 1014 | func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { | 
|  | 1015 | return module.Name() | 
|  | 1016 | } | 
|  | 1017 |  | 
|  | 1018 | func TestOutputFileForModule(t *testing.T) { | 
|  | 1019 | testcases := []struct { | 
|  | 1020 | name        string | 
|  | 1021 | module      blueprint.Module | 
|  | 1022 | tag         string | 
|  | 1023 | env         map[string]string | 
|  | 1024 | config      func(*config) | 
|  | 1025 | expected    string | 
|  | 1026 | missingDeps []string | 
|  | 1027 | }{ | 
|  | 1028 | { | 
|  | 1029 | name:     "SourceFileProducer", | 
|  | 1030 | module:   &sourceProducerTestModule{source: PathForTesting("foo.txt")}, | 
|  | 1031 | expected: "foo.txt", | 
|  | 1032 | }, | 
|  | 1033 | { | 
|  | 1034 | name:     "OutputFileProducer", | 
|  | 1035 | module:   &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, | 
|  | 1036 | expected: "foo.txt", | 
|  | 1037 | }, | 
|  | 1038 | { | 
|  | 1039 | name:     "OutputFileProducer_tag", | 
|  | 1040 | module:   &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, | 
|  | 1041 | tag:      "foo", | 
|  | 1042 | expected: "foo.txt", | 
|  | 1043 | }, | 
|  | 1044 | { | 
|  | 1045 | name: "OutputFileProducer_AllowMissingDependencies", | 
|  | 1046 | config: func(config *config) { | 
|  | 1047 | config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) | 
|  | 1048 | }, | 
|  | 1049 | module:      &outputFileProducerTestModule{}, | 
|  | 1050 | missingDeps: []string{"foo"}, | 
|  | 1051 | expected:    "missing_output_file/foo", | 
|  | 1052 | }, | 
|  | 1053 | } | 
|  | 1054 | for _, tt := range testcases { | 
|  | 1055 | config := TestConfig(buildDir, tt.env, "", nil) | 
|  | 1056 | if tt.config != nil { | 
|  | 1057 | tt.config(config.config) | 
|  | 1058 | } | 
|  | 1059 | ctx := &pathContextAddMissingDependenciesWrapper{ | 
|  | 1060 | PathContext: PathContextForTesting(config), | 
|  | 1061 | } | 
|  | 1062 | got := OutputFileForModule(ctx, tt.module, tt.tag) | 
|  | 1063 | AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) | 
|  | 1064 | AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) | 
|  | 1065 | } | 
|  | 1066 | } |