github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/paths_test.go (about) 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 17 import ( 18 "errors" 19 "fmt" 20 "reflect" 21 "strings" 22 "testing" 23 24 "github.com/google/blueprint/pathtools" 25 ) 26 27 type strsTestCase struct { 28 in []string 29 out string 30 err []error 31 } 32 33 var commonValidatePathTestCases = []strsTestCase{ 34 { 35 in: []string{""}, 36 out: "", 37 }, 38 { 39 in: []string{"a/b"}, 40 out: "a/b", 41 }, 42 { 43 in: []string{"a/b", "c"}, 44 out: "a/b/c", 45 }, 46 { 47 in: []string{"a/.."}, 48 out: ".", 49 }, 50 { 51 in: []string{"."}, 52 out: ".", 53 }, 54 { 55 in: []string{".."}, 56 out: "", 57 err: []error{errors.New("Path is outside directory: ..")}, 58 }, 59 { 60 in: []string{"../a"}, 61 out: "", 62 err: []error{errors.New("Path is outside directory: ../a")}, 63 }, 64 { 65 in: []string{"b/../../a"}, 66 out: "", 67 err: []error{errors.New("Path is outside directory: ../a")}, 68 }, 69 { 70 in: []string{"/a"}, 71 out: "", 72 err: []error{errors.New("Path is outside directory: /a")}, 73 }, 74 { 75 in: []string{"a", "../b"}, 76 out: "", 77 err: []error{errors.New("Path is outside directory: ../b")}, 78 }, 79 { 80 in: []string{"a", "b/../../c"}, 81 out: "", 82 err: []error{errors.New("Path is outside directory: ../c")}, 83 }, 84 { 85 in: []string{"a", "./.."}, 86 out: "", 87 err: []error{errors.New("Path is outside directory: ..")}, 88 }, 89 } 90 91 var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 92 { 93 in: []string{"$host/../$a"}, 94 out: "$a", 95 }, 96 }...) 97 98 var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 99 { 100 in: []string{"$host/../$a"}, 101 out: "", 102 err: []error{errors.New("Path contains invalid character($): $host/../$a")}, 103 }, 104 { 105 in: []string{"$host/.."}, 106 out: "", 107 err: []error{errors.New("Path contains invalid character($): $host/..")}, 108 }, 109 }...) 110 111 func TestValidateSafePath(t *testing.T) { 112 for _, testCase := range validateSafePathTestCases { 113 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 114 ctx := &configErrorWrapper{} 115 out, err := validateSafePath(testCase.in...) 116 if err != nil { 117 reportPathError(ctx, err) 118 } 119 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 120 }) 121 } 122 } 123 124 func TestValidatePath(t *testing.T) { 125 for _, testCase := range validatePathTestCases { 126 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 127 ctx := &configErrorWrapper{} 128 out, err := validatePath(testCase.in...) 129 if err != nil { 130 reportPathError(ctx, err) 131 } 132 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 133 }) 134 } 135 } 136 137 func TestOptionalPath(t *testing.T) { 138 var path OptionalPath 139 checkInvalidOptionalPath(t, path) 140 141 path = OptionalPathForPath(nil) 142 checkInvalidOptionalPath(t, path) 143 } 144 145 func checkInvalidOptionalPath(t *testing.T, path OptionalPath) { 146 t.Helper() 147 if path.Valid() { 148 t.Errorf("Uninitialized OptionalPath should not be valid") 149 } 150 if path.String() != "" { 151 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String()) 152 } 153 defer func() { 154 if r := recover(); r == nil { 155 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath") 156 } 157 }() 158 path.Path() 159 } 160 161 func check(t *testing.T, testType, testString string, 162 got interface{}, err []error, 163 expected interface{}, expectedErr []error) { 164 t.Helper() 165 166 printedTestCase := false 167 e := func(s string, expected, got interface{}) { 168 t.Helper() 169 if !printedTestCase { 170 t.Errorf("test case %s: %s", testType, testString) 171 printedTestCase = true 172 } 173 t.Errorf("incorrect %s", s) 174 t.Errorf(" expected: %s", p(expected)) 175 t.Errorf(" got: %s", p(got)) 176 } 177 178 if !reflect.DeepEqual(expectedErr, err) { 179 e("errors:", expectedErr, err) 180 } 181 182 if !reflect.DeepEqual(expected, got) { 183 e("output:", expected, got) 184 } 185 } 186 187 func p(in interface{}) string { 188 if v, ok := in.([]interface{}); ok { 189 s := make([]string, len(v)) 190 for i := range v { 191 s[i] = fmt.Sprintf("%#v", v[i]) 192 } 193 return "[" + strings.Join(s, ", ") + "]" 194 } else { 195 return fmt.Sprintf("%#v", in) 196 } 197 } 198 199 type moduleInstallPathContextImpl struct { 200 androidBaseContextImpl 201 202 inData bool 203 inSanitizerDir bool 204 } 205 206 func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem { 207 return pathtools.MockFs(nil) 208 } 209 210 func (m moduleInstallPathContextImpl) Config() Config { 211 return m.androidBaseContextImpl.config 212 } 213 214 func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {} 215 216 func (m moduleInstallPathContextImpl) InstallInData() bool { 217 return m.inData 218 } 219 220 func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool { 221 return m.inSanitizerDir 222 } 223 224 func TestPathForModuleInstall(t *testing.T) { 225 testConfig := TestConfig("", nil) 226 227 hostTarget := Target{Os: Linux} 228 deviceTarget := Target{Os: Android} 229 230 testCases := []struct { 231 name string 232 ctx *moduleInstallPathContextImpl 233 in []string 234 out string 235 }{ 236 { 237 name: "host binary", 238 ctx: &moduleInstallPathContextImpl{ 239 androidBaseContextImpl: androidBaseContextImpl{ 240 target: hostTarget, 241 }, 242 }, 243 in: []string{"bin", "my_test"}, 244 out: "host/linux-x86/bin/my_test", 245 }, 246 247 { 248 name: "system binary", 249 ctx: &moduleInstallPathContextImpl{ 250 androidBaseContextImpl: androidBaseContextImpl{ 251 target: deviceTarget, 252 }, 253 }, 254 in: []string{"bin", "my_test"}, 255 out: "target/product/test_device/system/bin/my_test", 256 }, 257 { 258 name: "vendor binary", 259 ctx: &moduleInstallPathContextImpl{ 260 androidBaseContextImpl: androidBaseContextImpl{ 261 target: deviceTarget, 262 kind: socSpecificModule, 263 }, 264 }, 265 in: []string{"bin", "my_test"}, 266 out: "target/product/test_device/vendor/bin/my_test", 267 }, 268 { 269 name: "odm binary", 270 ctx: &moduleInstallPathContextImpl{ 271 androidBaseContextImpl: androidBaseContextImpl{ 272 target: deviceTarget, 273 kind: deviceSpecificModule, 274 }, 275 }, 276 in: []string{"bin", "my_test"}, 277 out: "target/product/test_device/odm/bin/my_test", 278 }, 279 { 280 name: "product binary", 281 ctx: &moduleInstallPathContextImpl{ 282 androidBaseContextImpl: androidBaseContextImpl{ 283 target: deviceTarget, 284 kind: productSpecificModule, 285 }, 286 }, 287 in: []string{"bin", "my_test"}, 288 out: "target/product/test_device/product/bin/my_test", 289 }, 290 291 { 292 name: "system native test binary", 293 ctx: &moduleInstallPathContextImpl{ 294 androidBaseContextImpl: androidBaseContextImpl{ 295 target: deviceTarget, 296 }, 297 inData: true, 298 }, 299 in: []string{"nativetest", "my_test"}, 300 out: "target/product/test_device/data/nativetest/my_test", 301 }, 302 { 303 name: "vendor native test binary", 304 ctx: &moduleInstallPathContextImpl{ 305 androidBaseContextImpl: androidBaseContextImpl{ 306 target: deviceTarget, 307 kind: socSpecificModule, 308 }, 309 inData: true, 310 }, 311 in: []string{"nativetest", "my_test"}, 312 out: "target/product/test_device/data/nativetest/my_test", 313 }, 314 { 315 name: "odm native test binary", 316 ctx: &moduleInstallPathContextImpl{ 317 androidBaseContextImpl: androidBaseContextImpl{ 318 target: deviceTarget, 319 kind: deviceSpecificModule, 320 }, 321 inData: true, 322 }, 323 in: []string{"nativetest", "my_test"}, 324 out: "target/product/test_device/data/nativetest/my_test", 325 }, 326 { 327 name: "product native test binary", 328 ctx: &moduleInstallPathContextImpl{ 329 androidBaseContextImpl: androidBaseContextImpl{ 330 target: deviceTarget, 331 kind: productSpecificModule, 332 }, 333 inData: true, 334 }, 335 in: []string{"nativetest", "my_test"}, 336 out: "target/product/test_device/data/nativetest/my_test", 337 }, 338 339 { 340 name: "sanitized system binary", 341 ctx: &moduleInstallPathContextImpl{ 342 androidBaseContextImpl: androidBaseContextImpl{ 343 target: deviceTarget, 344 }, 345 inSanitizerDir: true, 346 }, 347 in: []string{"bin", "my_test"}, 348 out: "target/product/test_device/data/asan/system/bin/my_test", 349 }, 350 { 351 name: "sanitized vendor binary", 352 ctx: &moduleInstallPathContextImpl{ 353 androidBaseContextImpl: androidBaseContextImpl{ 354 target: deviceTarget, 355 kind: socSpecificModule, 356 }, 357 inSanitizerDir: true, 358 }, 359 in: []string{"bin", "my_test"}, 360 out: "target/product/test_device/data/asan/vendor/bin/my_test", 361 }, 362 { 363 name: "sanitized odm binary", 364 ctx: &moduleInstallPathContextImpl{ 365 androidBaseContextImpl: androidBaseContextImpl{ 366 target: deviceTarget, 367 kind: deviceSpecificModule, 368 }, 369 inSanitizerDir: true, 370 }, 371 in: []string{"bin", "my_test"}, 372 out: "target/product/test_device/data/asan/odm/bin/my_test", 373 }, 374 { 375 name: "sanitized product binary", 376 ctx: &moduleInstallPathContextImpl{ 377 androidBaseContextImpl: androidBaseContextImpl{ 378 target: deviceTarget, 379 kind: productSpecificModule, 380 }, 381 inSanitizerDir: true, 382 }, 383 in: []string{"bin", "my_test"}, 384 out: "target/product/test_device/data/asan/product/bin/my_test", 385 }, 386 387 { 388 name: "sanitized system native test binary", 389 ctx: &moduleInstallPathContextImpl{ 390 androidBaseContextImpl: androidBaseContextImpl{ 391 target: deviceTarget, 392 }, 393 inData: true, 394 inSanitizerDir: true, 395 }, 396 in: []string{"nativetest", "my_test"}, 397 out: "target/product/test_device/data/asan/data/nativetest/my_test", 398 }, 399 { 400 name: "sanitized vendor native test binary", 401 ctx: &moduleInstallPathContextImpl{ 402 androidBaseContextImpl: androidBaseContextImpl{ 403 target: deviceTarget, 404 kind: socSpecificModule, 405 }, 406 inData: true, 407 inSanitizerDir: true, 408 }, 409 in: []string{"nativetest", "my_test"}, 410 out: "target/product/test_device/data/asan/data/nativetest/my_test", 411 }, 412 { 413 name: "sanitized odm native test binary", 414 ctx: &moduleInstallPathContextImpl{ 415 androidBaseContextImpl: androidBaseContextImpl{ 416 target: deviceTarget, 417 kind: deviceSpecificModule, 418 }, 419 inData: true, 420 inSanitizerDir: true, 421 }, 422 in: []string{"nativetest", "my_test"}, 423 out: "target/product/test_device/data/asan/data/nativetest/my_test", 424 }, 425 { 426 name: "sanitized product native test binary", 427 ctx: &moduleInstallPathContextImpl{ 428 androidBaseContextImpl: androidBaseContextImpl{ 429 target: deviceTarget, 430 kind: productSpecificModule, 431 }, 432 inData: true, 433 inSanitizerDir: true, 434 }, 435 in: []string{"nativetest", "my_test"}, 436 out: "target/product/test_device/data/asan/data/nativetest/my_test", 437 }, 438 } 439 440 for _, tc := range testCases { 441 t.Run(tc.name, func(t *testing.T) { 442 tc.ctx.androidBaseContextImpl.config = testConfig 443 output := PathForModuleInstall(tc.ctx, tc.in...) 444 if output.basePath.path != tc.out { 445 t.Errorf("unexpected path:\n got: %q\nwant: %q\n", 446 output.basePath.path, 447 tc.out) 448 } 449 }) 450 } 451 } 452 453 func TestDirectorySortedPaths(t *testing.T) { 454 makePaths := func() Paths { 455 return Paths{ 456 PathForTesting("a.txt"), 457 PathForTesting("a/txt"), 458 PathForTesting("a/b/c"), 459 PathForTesting("a/b/d"), 460 PathForTesting("b"), 461 PathForTesting("b/b.txt"), 462 PathForTesting("a/a.txt"), 463 } 464 } 465 466 expected := []string{ 467 "a.txt", 468 "a/a.txt", 469 "a/b/c", 470 "a/b/d", 471 "a/txt", 472 "b", 473 "b/b.txt", 474 } 475 476 paths := makePaths() 477 reversePaths := ReversePaths(paths) 478 479 sortedPaths := PathsToDirectorySortedPaths(paths) 480 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths) 481 482 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) { 483 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected) 484 } 485 486 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) { 487 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected) 488 } 489 490 expectedA := []string{ 491 "a/a.txt", 492 "a/b/c", 493 "a/b/d", 494 "a/txt", 495 } 496 497 inA := sortedPaths.PathsInDirectory("a") 498 if !reflect.DeepEqual(inA.Strings(), expectedA) { 499 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA) 500 } 501 502 expectedA_B := []string{ 503 "a/b/c", 504 "a/b/d", 505 } 506 507 inA_B := sortedPaths.PathsInDirectory("a/b") 508 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) { 509 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B) 510 } 511 512 expectedB := []string{ 513 "b/b.txt", 514 } 515 516 inB := sortedPaths.PathsInDirectory("b") 517 if !reflect.DeepEqual(inB.Strings(), expectedB) { 518 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA) 519 } 520 }