blob: b1dfc28b0dd62b63285afb5d6d82b89c626e2825 [file] [log] [blame]
Dan Willemsen34cc69e2015-09-23 15:26:20 -07001// 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
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Dan Willemsen34cc69e2015-09-23 15:26:20 -070016
17import (
18 "errors"
19 "fmt"
Colin Cross937664a2019-03-06 10:17:32 -080020 "io/ioutil"
21 "os"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070022 "reflect"
23 "strings"
24 "testing"
Dan Willemsen00269f22017-07-06 16:59:48 -070025
26 "github.com/google/blueprint/pathtools"
Colin Cross8a497952019-03-05 22:25:09 -080027 "github.com/google/blueprint/proptools"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070028)
29
30type strsTestCase struct {
31 in []string
32 out string
33 err []error
34}
35
36var commonValidatePathTestCases = []strsTestCase{
37 {
38 in: []string{""},
39 out: "",
40 },
41 {
42 in: []string{"a/b"},
43 out: "a/b",
44 },
45 {
46 in: []string{"a/b", "c"},
47 out: "a/b/c",
48 },
49 {
50 in: []string{"a/.."},
51 out: ".",
52 },
53 {
54 in: []string{"."},
55 out: ".",
56 },
57 {
Dan Willemsen34cc69e2015-09-23 15:26:20 -070058 in: []string{"/a"},
59 out: "",
60 err: []error{errors.New("Path is outside directory: /a")},
61 },
Dan Willemsen34cc69e2015-09-23 15:26:20 -070062}
63
64var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
65 {
66 in: []string{"$host/../$a"},
67 out: "$a",
68 },
69}...)
70
71var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
72 {
73 in: []string{"$host/../$a"},
74 out: "",
75 err: []error{errors.New("Path contains invalid character($): $host/../$a")},
76 },
77 {
78 in: []string{"$host/.."},
79 out: "",
80 err: []error{errors.New("Path contains invalid character($): $host/..")},
81 },
82}...)
83
84func TestValidateSafePath(t *testing.T) {
85 for _, testCase := range validateSafePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -080086 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
87 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -080088 out, err := validateSafePath(testCase.in...)
89 if err != nil {
90 reportPathError(ctx, err)
91 }
Colin Crossdc75ae72018-02-22 13:48:13 -080092 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
93 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -070094 }
95}
96
97func TestValidatePath(t *testing.T) {
98 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -080099 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
100 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800101 out, err := validatePath(testCase.in...)
102 if err != nil {
103 reportPathError(ctx, err)
104 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800105 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
106 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700107 }
108}
109
110func TestOptionalPath(t *testing.T) {
111 var path OptionalPath
112 checkInvalidOptionalPath(t, path)
113
114 path = OptionalPathForPath(nil)
115 checkInvalidOptionalPath(t, path)
116}
117
118func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800119 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700120 if path.Valid() {
121 t.Errorf("Uninitialized OptionalPath should not be valid")
122 }
123 if path.String() != "" {
124 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
125 }
126 defer func() {
127 if r := recover(); r == nil {
128 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
129 }
130 }()
131 path.Path()
132}
133
134func check(t *testing.T, testType, testString string,
135 got interface{}, err []error,
136 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800137 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700138
139 printedTestCase := false
140 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800141 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700142 if !printedTestCase {
143 t.Errorf("test case %s: %s", testType, testString)
144 printedTestCase = true
145 }
146 t.Errorf("incorrect %s", s)
147 t.Errorf(" expected: %s", p(expected))
148 t.Errorf(" got: %s", p(got))
149 }
150
151 if !reflect.DeepEqual(expectedErr, err) {
152 e("errors:", expectedErr, err)
153 }
154
155 if !reflect.DeepEqual(expected, got) {
156 e("output:", expected, got)
157 }
158}
159
160func p(in interface{}) string {
161 if v, ok := in.([]interface{}); ok {
162 s := make([]string, len(v))
163 for i := range v {
164 s[i] = fmt.Sprintf("%#v", v[i])
165 }
166 return "[" + strings.Join(s, ", ") + "]"
167 } else {
168 return fmt.Sprintf("%#v", in)
169 }
170}
Dan Willemsen00269f22017-07-06 16:59:48 -0700171
172type moduleInstallPathContextImpl struct {
173 androidBaseContextImpl
174
175 inData bool
Jaewoong Jung1ffd7932019-09-11 10:25:18 -0700176 inTestcases bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700177 inSanitizerDir bool
Jiyong Parkf9332f12018-02-01 00:54:12 +0900178 inRecovery bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700179}
180
181func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
182 return pathtools.MockFs(nil)
183}
184
Colin Crossaabf6792017-11-29 00:27:14 -0800185func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700186 return m.androidBaseContextImpl.config
187}
188
189func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
190
191func (m moduleInstallPathContextImpl) InstallInData() bool {
192 return m.inData
193}
194
Jaewoong Jung1ffd7932019-09-11 10:25:18 -0700195func (m moduleInstallPathContextImpl) InstallInTestcases() bool {
196 return m.inTestcases
197}
198
Dan Willemsen00269f22017-07-06 16:59:48 -0700199func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
200 return m.inSanitizerDir
201}
202
Jiyong Parkf9332f12018-02-01 00:54:12 +0900203func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
204 return m.inRecovery
205}
206
Dan Willemsen00269f22017-07-06 16:59:48 -0700207func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700208 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700209
210 hostTarget := Target{Os: Linux}
211 deviceTarget := Target{Os: Android}
212
213 testCases := []struct {
214 name string
215 ctx *moduleInstallPathContextImpl
216 in []string
217 out string
218 }{
219 {
220 name: "host binary",
221 ctx: &moduleInstallPathContextImpl{
222 androidBaseContextImpl: androidBaseContextImpl{
223 target: hostTarget,
224 },
225 },
226 in: []string{"bin", "my_test"},
227 out: "host/linux-x86/bin/my_test",
228 },
229
230 {
231 name: "system binary",
232 ctx: &moduleInstallPathContextImpl{
233 androidBaseContextImpl: androidBaseContextImpl{
234 target: deviceTarget,
235 },
236 },
237 in: []string{"bin", "my_test"},
238 out: "target/product/test_device/system/bin/my_test",
239 },
240 {
241 name: "vendor binary",
242 ctx: &moduleInstallPathContextImpl{
243 androidBaseContextImpl: androidBaseContextImpl{
244 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900245 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700246 },
247 },
248 in: []string{"bin", "my_test"},
249 out: "target/product/test_device/vendor/bin/my_test",
250 },
Jiyong Park2db76922017-11-08 16:03:48 +0900251 {
252 name: "odm binary",
253 ctx: &moduleInstallPathContextImpl{
254 androidBaseContextImpl: androidBaseContextImpl{
255 target: deviceTarget,
256 kind: deviceSpecificModule,
257 },
258 },
259 in: []string{"bin", "my_test"},
260 out: "target/product/test_device/odm/bin/my_test",
261 },
262 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900263 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900264 ctx: &moduleInstallPathContextImpl{
265 androidBaseContextImpl: androidBaseContextImpl{
266 target: deviceTarget,
267 kind: productSpecificModule,
268 },
269 },
270 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900271 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900272 },
Dario Frenifd05a742018-05-29 13:28:54 +0100273 {
Dario Freni95cf7672018-08-17 00:57:57 +0100274 name: "product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100275 ctx: &moduleInstallPathContextImpl{
276 androidBaseContextImpl: androidBaseContextImpl{
277 target: deviceTarget,
278 kind: productServicesSpecificModule,
279 },
280 },
281 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100282 out: "target/product/test_device/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100283 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700284
285 {
286 name: "system native test binary",
287 ctx: &moduleInstallPathContextImpl{
288 androidBaseContextImpl: androidBaseContextImpl{
289 target: deviceTarget,
290 },
291 inData: true,
292 },
293 in: []string{"nativetest", "my_test"},
294 out: "target/product/test_device/data/nativetest/my_test",
295 },
296 {
297 name: "vendor native test binary",
298 ctx: &moduleInstallPathContextImpl{
299 androidBaseContextImpl: androidBaseContextImpl{
300 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900301 kind: socSpecificModule,
302 },
303 inData: true,
304 },
305 in: []string{"nativetest", "my_test"},
306 out: "target/product/test_device/data/nativetest/my_test",
307 },
308 {
309 name: "odm native test binary",
310 ctx: &moduleInstallPathContextImpl{
311 androidBaseContextImpl: androidBaseContextImpl{
312 target: deviceTarget,
313 kind: deviceSpecificModule,
314 },
315 inData: true,
316 },
317 in: []string{"nativetest", "my_test"},
318 out: "target/product/test_device/data/nativetest/my_test",
319 },
320 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900321 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900322 ctx: &moduleInstallPathContextImpl{
323 androidBaseContextImpl: androidBaseContextImpl{
324 target: deviceTarget,
325 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700326 },
327 inData: true,
328 },
329 in: []string{"nativetest", "my_test"},
330 out: "target/product/test_device/data/nativetest/my_test",
331 },
332
333 {
Dario Freni95cf7672018-08-17 00:57:57 +0100334 name: "product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100335 ctx: &moduleInstallPathContextImpl{
336 androidBaseContextImpl: androidBaseContextImpl{
337 target: deviceTarget,
338 kind: productServicesSpecificModule,
339 },
340 inData: true,
341 },
342 in: []string{"nativetest", "my_test"},
343 out: "target/product/test_device/data/nativetest/my_test",
344 },
345
346 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700347 name: "sanitized system binary",
348 ctx: &moduleInstallPathContextImpl{
349 androidBaseContextImpl: androidBaseContextImpl{
350 target: deviceTarget,
351 },
352 inSanitizerDir: true,
353 },
354 in: []string{"bin", "my_test"},
355 out: "target/product/test_device/data/asan/system/bin/my_test",
356 },
357 {
358 name: "sanitized vendor binary",
359 ctx: &moduleInstallPathContextImpl{
360 androidBaseContextImpl: androidBaseContextImpl{
361 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900362 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700363 },
364 inSanitizerDir: true,
365 },
366 in: []string{"bin", "my_test"},
367 out: "target/product/test_device/data/asan/vendor/bin/my_test",
368 },
Jiyong Park2db76922017-11-08 16:03:48 +0900369 {
370 name: "sanitized odm binary",
371 ctx: &moduleInstallPathContextImpl{
372 androidBaseContextImpl: androidBaseContextImpl{
373 target: deviceTarget,
374 kind: deviceSpecificModule,
375 },
376 inSanitizerDir: true,
377 },
378 in: []string{"bin", "my_test"},
379 out: "target/product/test_device/data/asan/odm/bin/my_test",
380 },
381 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900382 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900383 ctx: &moduleInstallPathContextImpl{
384 androidBaseContextImpl: androidBaseContextImpl{
385 target: deviceTarget,
386 kind: productSpecificModule,
387 },
388 inSanitizerDir: true,
389 },
390 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900391 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900392 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700393
394 {
Dario Freni95cf7672018-08-17 00:57:57 +0100395 name: "sanitized product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100396 ctx: &moduleInstallPathContextImpl{
397 androidBaseContextImpl: androidBaseContextImpl{
398 target: deviceTarget,
399 kind: productServicesSpecificModule,
400 },
401 inSanitizerDir: true,
402 },
403 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100404 out: "target/product/test_device/data/asan/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100405 },
406
407 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700408 name: "sanitized system native test binary",
409 ctx: &moduleInstallPathContextImpl{
410 androidBaseContextImpl: androidBaseContextImpl{
411 target: deviceTarget,
412 },
413 inData: true,
414 inSanitizerDir: true,
415 },
416 in: []string{"nativetest", "my_test"},
417 out: "target/product/test_device/data/asan/data/nativetest/my_test",
418 },
419 {
420 name: "sanitized vendor native test binary",
421 ctx: &moduleInstallPathContextImpl{
422 androidBaseContextImpl: androidBaseContextImpl{
423 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900424 kind: socSpecificModule,
425 },
426 inData: true,
427 inSanitizerDir: true,
428 },
429 in: []string{"nativetest", "my_test"},
430 out: "target/product/test_device/data/asan/data/nativetest/my_test",
431 },
432 {
433 name: "sanitized odm native test binary",
434 ctx: &moduleInstallPathContextImpl{
435 androidBaseContextImpl: androidBaseContextImpl{
436 target: deviceTarget,
437 kind: deviceSpecificModule,
438 },
439 inData: true,
440 inSanitizerDir: true,
441 },
442 in: []string{"nativetest", "my_test"},
443 out: "target/product/test_device/data/asan/data/nativetest/my_test",
444 },
445 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900446 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900447 ctx: &moduleInstallPathContextImpl{
448 androidBaseContextImpl: androidBaseContextImpl{
449 target: deviceTarget,
450 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700451 },
452 inData: true,
453 inSanitizerDir: true,
454 },
455 in: []string{"nativetest", "my_test"},
456 out: "target/product/test_device/data/asan/data/nativetest/my_test",
457 },
Dario Frenifd05a742018-05-29 13:28:54 +0100458 {
Dario Freni95cf7672018-08-17 00:57:57 +0100459 name: "sanitized product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100460 ctx: &moduleInstallPathContextImpl{
461 androidBaseContextImpl: androidBaseContextImpl{
462 target: deviceTarget,
463 kind: productServicesSpecificModule,
464 },
465 inData: true,
466 inSanitizerDir: true,
467 },
468 in: []string{"nativetest", "my_test"},
469 out: "target/product/test_device/data/asan/data/nativetest/my_test",
470 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700471 }
472
473 for _, tc := range testCases {
474 t.Run(tc.name, func(t *testing.T) {
475 tc.ctx.androidBaseContextImpl.config = testConfig
476 output := PathForModuleInstall(tc.ctx, tc.in...)
477 if output.basePath.path != tc.out {
478 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
479 output.basePath.path,
480 tc.out)
481 }
482 })
483 }
484}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700485
486func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800487 config := TestConfig("out", nil)
488
489 ctx := PathContextForTesting(config, map[string][]byte{
490 "a.txt": nil,
491 "a/txt": nil,
492 "a/b/c": nil,
493 "a/b/d": nil,
494 "b": nil,
495 "b/b.txt": nil,
496 "a/a.txt": nil,
497 })
498
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700499 makePaths := func() Paths {
500 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800501 PathForSource(ctx, "a.txt"),
502 PathForSource(ctx, "a/txt"),
503 PathForSource(ctx, "a/b/c"),
504 PathForSource(ctx, "a/b/d"),
505 PathForSource(ctx, "b"),
506 PathForSource(ctx, "b/b.txt"),
507 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700508 }
509 }
510
511 expected := []string{
512 "a.txt",
513 "a/a.txt",
514 "a/b/c",
515 "a/b/d",
516 "a/txt",
517 "b",
518 "b/b.txt",
519 }
520
521 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700522 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700523
524 sortedPaths := PathsToDirectorySortedPaths(paths)
525 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
526
527 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
528 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
529 }
530
531 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
532 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
533 }
534
535 expectedA := []string{
536 "a/a.txt",
537 "a/b/c",
538 "a/b/d",
539 "a/txt",
540 }
541
542 inA := sortedPaths.PathsInDirectory("a")
543 if !reflect.DeepEqual(inA.Strings(), expectedA) {
544 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
545 }
546
547 expectedA_B := []string{
548 "a/b/c",
549 "a/b/d",
550 }
551
552 inA_B := sortedPaths.PathsInDirectory("a/b")
553 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
554 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
555 }
556
557 expectedB := []string{
558 "b/b.txt",
559 }
560
561 inB := sortedPaths.PathsInDirectory("b")
562 if !reflect.DeepEqual(inB.Strings(), expectedB) {
563 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
564 }
565}
Colin Cross43f08db2018-11-12 10:13:39 -0800566
567func TestMaybeRel(t *testing.T) {
568 testCases := []struct {
569 name string
570 base string
571 target string
572 out string
573 isRel bool
574 }{
575 {
576 name: "normal",
577 base: "a/b/c",
578 target: "a/b/c/d",
579 out: "d",
580 isRel: true,
581 },
582 {
583 name: "parent",
584 base: "a/b/c/d",
585 target: "a/b/c",
586 isRel: false,
587 },
588 {
589 name: "not relative",
590 base: "a/b",
591 target: "c/d",
592 isRel: false,
593 },
594 {
595 name: "abs1",
596 base: "/a",
597 target: "a",
598 isRel: false,
599 },
600 {
601 name: "abs2",
602 base: "a",
603 target: "/a",
604 isRel: false,
605 },
606 }
607
608 for _, testCase := range testCases {
609 t.Run(testCase.name, func(t *testing.T) {
610 ctx := &configErrorWrapper{}
Colin Cross43f08db2018-11-12 10:13:39 -0800611 if len(ctx.errors) > 0 {
612 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
613 testCase.base, testCase.target, ctx.errors)
614 }
Colin Cross43f08db2018-11-12 10:13:39 -0800615 })
616 }
617}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800618
619func TestPathForSource(t *testing.T) {
620 testCases := []struct {
621 name string
622 buildDir string
623 src string
624 err string
625 }{
626 {
627 name: "normal",
628 buildDir: "out",
629 src: "a/b/c",
630 },
631 {
632 name: "abs",
633 buildDir: "out",
634 src: "/a/b/c",
635 err: "is outside directory",
636 },
637 {
638 name: "in out dir",
639 buildDir: "out",
640 src: "out/a/b/c",
641 err: "is in output",
642 },
643 }
644
645 funcs := []struct {
646 name string
647 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
648 }{
649 {"pathForSource", pathForSource},
650 {"safePathForSource", safePathForSource},
651 }
652
653 for _, f := range funcs {
654 t.Run(f.name, func(t *testing.T) {
655 for _, test := range testCases {
656 t.Run(test.name, func(t *testing.T) {
657 testConfig := TestConfig(test.buildDir, nil)
658 ctx := &configErrorWrapper{config: testConfig}
659 _, err := f.f(ctx, test.src)
660 if len(ctx.errors) > 0 {
661 t.Fatalf("unexpected errors %v", ctx.errors)
662 }
663 if err != nil {
664 if test.err == "" {
665 t.Fatalf("unexpected error %q", err.Error())
666 } else if !strings.Contains(err.Error(), test.err) {
667 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
668 }
669 } else {
670 if test.err != "" {
671 t.Fatalf("missing error %q", test.err)
672 }
673 }
674 })
675 }
676 })
677 }
678}
Colin Cross8854a5a2019-02-11 14:14:16 -0800679
Colin Cross8a497952019-03-05 22:25:09 -0800680type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800681 ModuleBase
682 props struct {
683 Srcs []string `android:"path"`
684 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800685
686 Src *string `android:"path"`
Colin Crossc6de83c2019-03-18 12:12:48 -0700687
688 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800689 }
690
Colin Cross8a497952019-03-05 22:25:09 -0800691 src string
692 rel string
693
694 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800695 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800696
697 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800698}
699
Colin Cross8a497952019-03-05 22:25:09 -0800700func pathForModuleSrcTestModuleFactory() Module {
701 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800702 module.AddProperties(&module.props)
703 InitAndroidModule(module)
704 return module
705}
706
Colin Cross8a497952019-03-05 22:25:09 -0800707func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossc6de83c2019-03-18 12:12:48 -0700708 var srcs Paths
709 if p.props.Module_handles_missing_deps {
710 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
711 } else {
712 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
713 }
Colin Cross8a497952019-03-05 22:25:09 -0800714 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800715
Colin Cross8a497952019-03-05 22:25:09 -0800716 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800717 p.rels = append(p.rels, src.Rel())
718 }
Colin Cross8a497952019-03-05 22:25:09 -0800719
720 if p.props.Src != nil {
721 src := PathForModuleSrc(ctx, *p.props.Src)
722 if src != nil {
723 p.src = src.String()
724 p.rel = src.Rel()
725 }
726 }
727
Colin Crossc6de83c2019-03-18 12:12:48 -0700728 if !p.props.Module_handles_missing_deps {
729 p.missingDeps = ctx.GetMissingDependencies()
730 }
Colin Cross8a497952019-03-05 22:25:09 -0800731}
732
733type pathForModuleSrcTestCase struct {
734 name string
735 bp string
736 srcs []string
737 rels []string
738 src string
739 rel string
740}
741
742func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
743 for _, test := range tests {
744 t.Run(test.name, func(t *testing.T) {
745 config := TestConfig(buildDir, nil)
746 ctx := NewTestContext()
747
748 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
749 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
750
751 fgBp := `
752 filegroup {
753 name: "a",
754 srcs: ["src/a"],
755 }
756 `
757
758 mockFS := map[string][]byte{
759 "fg/Android.bp": []byte(fgBp),
760 "foo/Android.bp": []byte(test.bp),
761 "fg/src/a": nil,
762 "foo/src/b": nil,
763 "foo/src/c": nil,
764 "foo/src/d": nil,
765 "foo/src/e/e": nil,
766 "foo/src_special/$": nil,
767 }
768
769 ctx.MockFileSystem(mockFS)
770
771 ctx.Register()
772 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
773 FailIfErrored(t, errs)
774 _, errs = ctx.PrepareBuildActions(config)
775 FailIfErrored(t, errs)
776
777 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
778
779 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
780 t.Errorf("want srcs %q, got %q", w, g)
781 }
782
783 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
784 t.Errorf("want rels %q, got %q", w, g)
785 }
786
787 if g, w := m.src, test.src; g != w {
788 t.Errorf("want src %q, got %q", w, g)
789 }
790
791 if g, w := m.rel, test.rel; g != w {
792 t.Errorf("want rel %q, got %q", w, g)
793 }
794 })
795 }
Colin Cross937664a2019-03-06 10:17:32 -0800796}
797
Colin Cross8a497952019-03-05 22:25:09 -0800798func TestPathsForModuleSrc(t *testing.T) {
799 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800800 {
801 name: "path",
802 bp: `
803 test {
804 name: "foo",
805 srcs: ["src/b"],
806 }`,
807 srcs: []string{"foo/src/b"},
808 rels: []string{"src/b"},
809 },
810 {
811 name: "glob",
812 bp: `
813 test {
814 name: "foo",
815 srcs: [
816 "src/*",
817 "src/e/*",
818 ],
819 }`,
820 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
821 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
822 },
823 {
824 name: "recursive glob",
825 bp: `
826 test {
827 name: "foo",
828 srcs: ["src/**/*"],
829 }`,
830 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
831 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
832 },
833 {
834 name: "filegroup",
835 bp: `
836 test {
837 name: "foo",
838 srcs: [":a"],
839 }`,
840 srcs: []string{"fg/src/a"},
841 rels: []string{"src/a"},
842 },
843 {
844 name: "special characters glob",
845 bp: `
846 test {
847 name: "foo",
848 srcs: ["src_special/*"],
849 }`,
850 srcs: []string{"foo/src_special/$"},
851 rels: []string{"src_special/$"},
852 },
853 }
854
Colin Cross8a497952019-03-05 22:25:09 -0800855 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test")
856 if err != nil {
857 t.Fatal(err)
858 }
859 defer os.RemoveAll(buildDir)
860
861 testPathForModuleSrc(t, buildDir, tests)
862}
863
864func TestPathForModuleSrc(t *testing.T) {
865 tests := []pathForModuleSrcTestCase{
866 {
867 name: "path",
868 bp: `
869 test {
870 name: "foo",
871 src: "src/b",
872 }`,
873 src: "foo/src/b",
874 rel: "src/b",
875 },
876 {
877 name: "glob",
878 bp: `
879 test {
880 name: "foo",
881 src: "src/e/*",
882 }`,
883 src: "foo/src/e/e",
884 rel: "src/e/e",
885 },
886 {
887 name: "filegroup",
888 bp: `
889 test {
890 name: "foo",
891 src: ":a",
892 }`,
893 src: "fg/src/a",
894 rel: "src/a",
895 },
896 {
897 name: "special characters glob",
898 bp: `
899 test {
900 name: "foo",
901 src: "src_special/*",
902 }`,
903 src: "foo/src_special/$",
904 rel: "src_special/$",
905 },
906 }
907
Colin Cross937664a2019-03-06 10:17:32 -0800908 buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
909 if err != nil {
910 t.Fatal(err)
911 }
912 defer os.RemoveAll(buildDir)
913
Colin Cross8a497952019-03-05 22:25:09 -0800914 testPathForModuleSrc(t, buildDir, tests)
915}
Colin Cross937664a2019-03-06 10:17:32 -0800916
Colin Cross8a497952019-03-05 22:25:09 -0800917func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
918 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test")
919 if err != nil {
920 t.Fatal(err)
Colin Cross937664a2019-03-06 10:17:32 -0800921 }
Colin Cross8a497952019-03-05 22:25:09 -0800922 defer os.RemoveAll(buildDir)
923
924 config := TestConfig(buildDir, nil)
925 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
926
927 ctx := NewTestContext()
928 ctx.SetAllowMissingDependencies(true)
929
930 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
931
932 bp := `
933 test {
934 name: "foo",
935 srcs: [":a"],
936 exclude_srcs: [":b"],
937 src: ":c",
938 }
Colin Crossc6de83c2019-03-18 12:12:48 -0700939
940 test {
941 name: "bar",
942 srcs: [":d"],
943 exclude_srcs: [":e"],
944 module_handles_missing_deps: true,
945 }
Colin Cross8a497952019-03-05 22:25:09 -0800946 `
947
948 mockFS := map[string][]byte{
949 "Android.bp": []byte(bp),
950 }
951
952 ctx.MockFileSystem(mockFS)
953
954 ctx.Register()
955 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
956 FailIfErrored(t, errs)
957 _, errs = ctx.PrepareBuildActions(config)
958 FailIfErrored(t, errs)
959
960 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
961
962 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossc6de83c2019-03-18 12:12:48 -0700963 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -0800964 }
965
966 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossc6de83c2019-03-18 12:12:48 -0700967 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -0800968 }
969
970 if g, w := foo.src, ""; g != w {
Colin Crossc6de83c2019-03-18 12:12:48 -0700971 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -0800972 }
973
Colin Crossc6de83c2019-03-18 12:12:48 -0700974 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
975
976 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
977 t.Errorf("want bar missing deps %q, got %q", w, g)
978 }
979
980 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
981 t.Errorf("want bar srcs %q, got %q", w, g)
982 }
Colin Cross937664a2019-03-06 10:17:32 -0800983}
984
Colin Cross8854a5a2019-02-11 14:14:16 -0800985func ExampleOutputPath_ReplaceExtension() {
986 ctx := &configErrorWrapper{
987 config: TestConfig("out", nil),
988 }
Colin Cross2cdd5df2019-02-25 10:25:24 -0800989 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -0800990 p2 := p.ReplaceExtension(ctx, "oat")
991 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -0800992 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -0800993
994 // Output:
995 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -0800996 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -0800997}
Colin Cross40e33732019-02-15 11:08:35 -0800998
999func ExampleOutputPath_FileInSameDir() {
1000 ctx := &configErrorWrapper{
1001 config: TestConfig("out", nil),
1002 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001003 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001004 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1005 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001006 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001007
1008 // Output:
1009 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001010 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001011}