blob: cadf371bcec2c2b60374697ab563eac8f1107aef [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"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070027)
28
29type strsTestCase struct {
30 in []string
31 out string
32 err []error
33}
34
35var commonValidatePathTestCases = []strsTestCase{
36 {
37 in: []string{""},
38 out: "",
39 },
40 {
41 in: []string{"a/b"},
42 out: "a/b",
43 },
44 {
45 in: []string{"a/b", "c"},
46 out: "a/b/c",
47 },
48 {
49 in: []string{"a/.."},
50 out: ".",
51 },
52 {
53 in: []string{"."},
54 out: ".",
55 },
56 {
57 in: []string{".."},
58 out: "",
59 err: []error{errors.New("Path is outside directory: ..")},
60 },
61 {
62 in: []string{"../a"},
63 out: "",
64 err: []error{errors.New("Path is outside directory: ../a")},
65 },
66 {
67 in: []string{"b/../../a"},
68 out: "",
69 err: []error{errors.New("Path is outside directory: ../a")},
70 },
71 {
72 in: []string{"/a"},
73 out: "",
74 err: []error{errors.New("Path is outside directory: /a")},
75 },
Dan Willemsen80a7c2a2015-12-21 14:57:11 -080076 {
77 in: []string{"a", "../b"},
78 out: "",
79 err: []error{errors.New("Path is outside directory: ../b")},
80 },
81 {
82 in: []string{"a", "b/../../c"},
83 out: "",
84 err: []error{errors.New("Path is outside directory: ../c")},
85 },
86 {
87 in: []string{"a", "./.."},
88 out: "",
89 err: []error{errors.New("Path is outside directory: ..")},
90 },
Dan Willemsen34cc69e2015-09-23 15:26:20 -070091}
92
93var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
94 {
95 in: []string{"$host/../$a"},
96 out: "$a",
97 },
98}...)
99
100var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
101 {
102 in: []string{"$host/../$a"},
103 out: "",
104 err: []error{errors.New("Path contains invalid character($): $host/../$a")},
105 },
106 {
107 in: []string{"$host/.."},
108 out: "",
109 err: []error{errors.New("Path contains invalid character($): $host/..")},
110 },
111}...)
112
113func TestValidateSafePath(t *testing.T) {
114 for _, testCase := range validateSafePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800115 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
116 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800117 out, err := validateSafePath(testCase.in...)
118 if err != nil {
119 reportPathError(ctx, err)
120 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800121 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
122 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700123 }
124}
125
126func TestValidatePath(t *testing.T) {
127 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800128 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
129 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800130 out, err := validatePath(testCase.in...)
131 if err != nil {
132 reportPathError(ctx, err)
133 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800134 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
135 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700136 }
137}
138
139func TestOptionalPath(t *testing.T) {
140 var path OptionalPath
141 checkInvalidOptionalPath(t, path)
142
143 path = OptionalPathForPath(nil)
144 checkInvalidOptionalPath(t, path)
145}
146
147func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800148 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700149 if path.Valid() {
150 t.Errorf("Uninitialized OptionalPath should not be valid")
151 }
152 if path.String() != "" {
153 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
154 }
155 defer func() {
156 if r := recover(); r == nil {
157 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
158 }
159 }()
160 path.Path()
161}
162
163func check(t *testing.T, testType, testString string,
164 got interface{}, err []error,
165 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800166 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700167
168 printedTestCase := false
169 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800170 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700171 if !printedTestCase {
172 t.Errorf("test case %s: %s", testType, testString)
173 printedTestCase = true
174 }
175 t.Errorf("incorrect %s", s)
176 t.Errorf(" expected: %s", p(expected))
177 t.Errorf(" got: %s", p(got))
178 }
179
180 if !reflect.DeepEqual(expectedErr, err) {
181 e("errors:", expectedErr, err)
182 }
183
184 if !reflect.DeepEqual(expected, got) {
185 e("output:", expected, got)
186 }
187}
188
189func p(in interface{}) string {
190 if v, ok := in.([]interface{}); ok {
191 s := make([]string, len(v))
192 for i := range v {
193 s[i] = fmt.Sprintf("%#v", v[i])
194 }
195 return "[" + strings.Join(s, ", ") + "]"
196 } else {
197 return fmt.Sprintf("%#v", in)
198 }
199}
Dan Willemsen00269f22017-07-06 16:59:48 -0700200
201type moduleInstallPathContextImpl struct {
202 androidBaseContextImpl
203
204 inData bool
205 inSanitizerDir bool
Jiyong Parkf9332f12018-02-01 00:54:12 +0900206 inRecovery bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700207}
208
209func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
210 return pathtools.MockFs(nil)
211}
212
Colin Crossaabf6792017-11-29 00:27:14 -0800213func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700214 return m.androidBaseContextImpl.config
215}
216
217func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
218
219func (m moduleInstallPathContextImpl) InstallInData() bool {
220 return m.inData
221}
222
223func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
224 return m.inSanitizerDir
225}
226
Jiyong Parkf9332f12018-02-01 00:54:12 +0900227func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
228 return m.inRecovery
229}
230
Dan Willemsen00269f22017-07-06 16:59:48 -0700231func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700232 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700233
234 hostTarget := Target{Os: Linux}
235 deviceTarget := Target{Os: Android}
236
237 testCases := []struct {
238 name string
239 ctx *moduleInstallPathContextImpl
240 in []string
241 out string
242 }{
243 {
244 name: "host binary",
245 ctx: &moduleInstallPathContextImpl{
246 androidBaseContextImpl: androidBaseContextImpl{
247 target: hostTarget,
248 },
249 },
250 in: []string{"bin", "my_test"},
251 out: "host/linux-x86/bin/my_test",
252 },
253
254 {
255 name: "system binary",
256 ctx: &moduleInstallPathContextImpl{
257 androidBaseContextImpl: androidBaseContextImpl{
258 target: deviceTarget,
259 },
260 },
261 in: []string{"bin", "my_test"},
262 out: "target/product/test_device/system/bin/my_test",
263 },
264 {
265 name: "vendor binary",
266 ctx: &moduleInstallPathContextImpl{
267 androidBaseContextImpl: androidBaseContextImpl{
268 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900269 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700270 },
271 },
272 in: []string{"bin", "my_test"},
273 out: "target/product/test_device/vendor/bin/my_test",
274 },
Jiyong Park2db76922017-11-08 16:03:48 +0900275 {
276 name: "odm binary",
277 ctx: &moduleInstallPathContextImpl{
278 androidBaseContextImpl: androidBaseContextImpl{
279 target: deviceTarget,
280 kind: deviceSpecificModule,
281 },
282 },
283 in: []string{"bin", "my_test"},
284 out: "target/product/test_device/odm/bin/my_test",
285 },
286 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900287 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900288 ctx: &moduleInstallPathContextImpl{
289 androidBaseContextImpl: androidBaseContextImpl{
290 target: deviceTarget,
291 kind: productSpecificModule,
292 },
293 },
294 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900295 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900296 },
Dario Frenifd05a742018-05-29 13:28:54 +0100297 {
Dario Freni95cf7672018-08-17 00:57:57 +0100298 name: "product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100299 ctx: &moduleInstallPathContextImpl{
300 androidBaseContextImpl: androidBaseContextImpl{
301 target: deviceTarget,
302 kind: productServicesSpecificModule,
303 },
304 },
305 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100306 out: "target/product/test_device/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100307 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700308
309 {
310 name: "system native test binary",
311 ctx: &moduleInstallPathContextImpl{
312 androidBaseContextImpl: androidBaseContextImpl{
313 target: deviceTarget,
314 },
315 inData: true,
316 },
317 in: []string{"nativetest", "my_test"},
318 out: "target/product/test_device/data/nativetest/my_test",
319 },
320 {
321 name: "vendor native test binary",
322 ctx: &moduleInstallPathContextImpl{
323 androidBaseContextImpl: androidBaseContextImpl{
324 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900325 kind: socSpecificModule,
326 },
327 inData: true,
328 },
329 in: []string{"nativetest", "my_test"},
330 out: "target/product/test_device/data/nativetest/my_test",
331 },
332 {
333 name: "odm native test binary",
334 ctx: &moduleInstallPathContextImpl{
335 androidBaseContextImpl: androidBaseContextImpl{
336 target: deviceTarget,
337 kind: deviceSpecificModule,
338 },
339 inData: true,
340 },
341 in: []string{"nativetest", "my_test"},
342 out: "target/product/test_device/data/nativetest/my_test",
343 },
344 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900345 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900346 ctx: &moduleInstallPathContextImpl{
347 androidBaseContextImpl: androidBaseContextImpl{
348 target: deviceTarget,
349 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700350 },
351 inData: true,
352 },
353 in: []string{"nativetest", "my_test"},
354 out: "target/product/test_device/data/nativetest/my_test",
355 },
356
357 {
Dario Freni95cf7672018-08-17 00:57:57 +0100358 name: "product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100359 ctx: &moduleInstallPathContextImpl{
360 androidBaseContextImpl: androidBaseContextImpl{
361 target: deviceTarget,
362 kind: productServicesSpecificModule,
363 },
364 inData: true,
365 },
366 in: []string{"nativetest", "my_test"},
367 out: "target/product/test_device/data/nativetest/my_test",
368 },
369
370 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700371 name: "sanitized system binary",
372 ctx: &moduleInstallPathContextImpl{
373 androidBaseContextImpl: androidBaseContextImpl{
374 target: deviceTarget,
375 },
376 inSanitizerDir: true,
377 },
378 in: []string{"bin", "my_test"},
379 out: "target/product/test_device/data/asan/system/bin/my_test",
380 },
381 {
382 name: "sanitized vendor binary",
383 ctx: &moduleInstallPathContextImpl{
384 androidBaseContextImpl: androidBaseContextImpl{
385 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900386 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700387 },
388 inSanitizerDir: true,
389 },
390 in: []string{"bin", "my_test"},
391 out: "target/product/test_device/data/asan/vendor/bin/my_test",
392 },
Jiyong Park2db76922017-11-08 16:03:48 +0900393 {
394 name: "sanitized odm binary",
395 ctx: &moduleInstallPathContextImpl{
396 androidBaseContextImpl: androidBaseContextImpl{
397 target: deviceTarget,
398 kind: deviceSpecificModule,
399 },
400 inSanitizerDir: true,
401 },
402 in: []string{"bin", "my_test"},
403 out: "target/product/test_device/data/asan/odm/bin/my_test",
404 },
405 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900406 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900407 ctx: &moduleInstallPathContextImpl{
408 androidBaseContextImpl: androidBaseContextImpl{
409 target: deviceTarget,
410 kind: productSpecificModule,
411 },
412 inSanitizerDir: true,
413 },
414 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900415 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900416 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700417
418 {
Dario Freni95cf7672018-08-17 00:57:57 +0100419 name: "sanitized product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100420 ctx: &moduleInstallPathContextImpl{
421 androidBaseContextImpl: androidBaseContextImpl{
422 target: deviceTarget,
423 kind: productServicesSpecificModule,
424 },
425 inSanitizerDir: true,
426 },
427 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100428 out: "target/product/test_device/data/asan/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100429 },
430
431 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700432 name: "sanitized system native test binary",
433 ctx: &moduleInstallPathContextImpl{
434 androidBaseContextImpl: androidBaseContextImpl{
435 target: deviceTarget,
436 },
437 inData: true,
438 inSanitizerDir: true,
439 },
440 in: []string{"nativetest", "my_test"},
441 out: "target/product/test_device/data/asan/data/nativetest/my_test",
442 },
443 {
444 name: "sanitized vendor native test binary",
445 ctx: &moduleInstallPathContextImpl{
446 androidBaseContextImpl: androidBaseContextImpl{
447 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900448 kind: socSpecificModule,
449 },
450 inData: true,
451 inSanitizerDir: true,
452 },
453 in: []string{"nativetest", "my_test"},
454 out: "target/product/test_device/data/asan/data/nativetest/my_test",
455 },
456 {
457 name: "sanitized odm native test binary",
458 ctx: &moduleInstallPathContextImpl{
459 androidBaseContextImpl: androidBaseContextImpl{
460 target: deviceTarget,
461 kind: deviceSpecificModule,
462 },
463 inData: true,
464 inSanitizerDir: true,
465 },
466 in: []string{"nativetest", "my_test"},
467 out: "target/product/test_device/data/asan/data/nativetest/my_test",
468 },
469 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900470 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900471 ctx: &moduleInstallPathContextImpl{
472 androidBaseContextImpl: androidBaseContextImpl{
473 target: deviceTarget,
474 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700475 },
476 inData: true,
477 inSanitizerDir: true,
478 },
479 in: []string{"nativetest", "my_test"},
480 out: "target/product/test_device/data/asan/data/nativetest/my_test",
481 },
Dario Frenifd05a742018-05-29 13:28:54 +0100482 {
Dario Freni95cf7672018-08-17 00:57:57 +0100483 name: "sanitized product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100484 ctx: &moduleInstallPathContextImpl{
485 androidBaseContextImpl: androidBaseContextImpl{
486 target: deviceTarget,
487 kind: productServicesSpecificModule,
488 },
489 inData: true,
490 inSanitizerDir: true,
491 },
492 in: []string{"nativetest", "my_test"},
493 out: "target/product/test_device/data/asan/data/nativetest/my_test",
494 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700495 }
496
497 for _, tc := range testCases {
498 t.Run(tc.name, func(t *testing.T) {
499 tc.ctx.androidBaseContextImpl.config = testConfig
500 output := PathForModuleInstall(tc.ctx, tc.in...)
501 if output.basePath.path != tc.out {
502 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
503 output.basePath.path,
504 tc.out)
505 }
506 })
507 }
508}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700509
510func TestDirectorySortedPaths(t *testing.T) {
511 makePaths := func() Paths {
512 return Paths{
513 PathForTesting("a.txt"),
514 PathForTesting("a/txt"),
515 PathForTesting("a/b/c"),
516 PathForTesting("a/b/d"),
517 PathForTesting("b"),
518 PathForTesting("b/b.txt"),
519 PathForTesting("a/a.txt"),
520 }
521 }
522
523 expected := []string{
524 "a.txt",
525 "a/a.txt",
526 "a/b/c",
527 "a/b/d",
528 "a/txt",
529 "b",
530 "b/b.txt",
531 }
532
533 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700534 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700535
536 sortedPaths := PathsToDirectorySortedPaths(paths)
537 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
538
539 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
540 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
541 }
542
543 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
544 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
545 }
546
547 expectedA := []string{
548 "a/a.txt",
549 "a/b/c",
550 "a/b/d",
551 "a/txt",
552 }
553
554 inA := sortedPaths.PathsInDirectory("a")
555 if !reflect.DeepEqual(inA.Strings(), expectedA) {
556 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
557 }
558
559 expectedA_B := []string{
560 "a/b/c",
561 "a/b/d",
562 }
563
564 inA_B := sortedPaths.PathsInDirectory("a/b")
565 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
566 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
567 }
568
569 expectedB := []string{
570 "b/b.txt",
571 }
572
573 inB := sortedPaths.PathsInDirectory("b")
574 if !reflect.DeepEqual(inB.Strings(), expectedB) {
575 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
576 }
577}
Colin Cross43f08db2018-11-12 10:13:39 -0800578
579func TestMaybeRel(t *testing.T) {
580 testCases := []struct {
581 name string
582 base string
583 target string
584 out string
585 isRel bool
586 }{
587 {
588 name: "normal",
589 base: "a/b/c",
590 target: "a/b/c/d",
591 out: "d",
592 isRel: true,
593 },
594 {
595 name: "parent",
596 base: "a/b/c/d",
597 target: "a/b/c",
598 isRel: false,
599 },
600 {
601 name: "not relative",
602 base: "a/b",
603 target: "c/d",
604 isRel: false,
605 },
606 {
607 name: "abs1",
608 base: "/a",
609 target: "a",
610 isRel: false,
611 },
612 {
613 name: "abs2",
614 base: "a",
615 target: "/a",
616 isRel: false,
617 },
618 }
619
620 for _, testCase := range testCases {
621 t.Run(testCase.name, func(t *testing.T) {
622 ctx := &configErrorWrapper{}
623 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
624 if len(ctx.errors) > 0 {
625 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
626 testCase.base, testCase.target, ctx.errors)
627 }
628 if isRel != testCase.isRel || out != testCase.out {
629 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
630 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
631 }
632 })
633 }
634}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800635
636func TestPathForSource(t *testing.T) {
637 testCases := []struct {
638 name string
639 buildDir string
640 src string
641 err string
642 }{
643 {
644 name: "normal",
645 buildDir: "out",
646 src: "a/b/c",
647 },
648 {
649 name: "abs",
650 buildDir: "out",
651 src: "/a/b/c",
652 err: "is outside directory",
653 },
654 {
655 name: "in out dir",
656 buildDir: "out",
657 src: "out/a/b/c",
658 err: "is in output",
659 },
660 }
661
662 funcs := []struct {
663 name string
664 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
665 }{
666 {"pathForSource", pathForSource},
667 {"safePathForSource", safePathForSource},
668 }
669
670 for _, f := range funcs {
671 t.Run(f.name, func(t *testing.T) {
672 for _, test := range testCases {
673 t.Run(test.name, func(t *testing.T) {
674 testConfig := TestConfig(test.buildDir, nil)
675 ctx := &configErrorWrapper{config: testConfig}
676 _, err := f.f(ctx, test.src)
677 if len(ctx.errors) > 0 {
678 t.Fatalf("unexpected errors %v", ctx.errors)
679 }
680 if err != nil {
681 if test.err == "" {
682 t.Fatalf("unexpected error %q", err.Error())
683 } else if !strings.Contains(err.Error(), test.err) {
684 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
685 }
686 } else {
687 if test.err != "" {
688 t.Fatalf("missing error %q", test.err)
689 }
690 }
691 })
692 }
693 })
694 }
695}
Colin Cross8854a5a2019-02-11 14:14:16 -0800696
Colin Cross937664a2019-03-06 10:17:32 -0800697type expandSourcesTestModule struct {
698 ModuleBase
699 props struct {
700 Srcs []string `android:"path"`
701 Exclude_srcs []string `android:"path"`
702 }
703
704 srcs Paths
705 rels []string
706}
707
708func expandSourcesTestModuleFactory() Module {
709 module := &expandSourcesTestModule{}
710 module.AddProperties(&module.props)
711 InitAndroidModule(module)
712 return module
713}
714
715func (p *expandSourcesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
716 p.srcs = ctx.ExpandSources(p.props.Srcs, p.props.Exclude_srcs)
717
718 for _, src := range p.srcs {
719 p.rels = append(p.rels, src.Rel())
720 }
721}
722
723func TestExpandSources(t *testing.T) {
724 tests := []struct {
725 name string
726 bp string
727 srcs []string
728 rels []string
729 }{
730 {
731 name: "path",
732 bp: `
733 test {
734 name: "foo",
735 srcs: ["src/b"],
736 }`,
737 srcs: []string{"foo/src/b"},
738 rels: []string{"src/b"},
739 },
740 {
741 name: "glob",
742 bp: `
743 test {
744 name: "foo",
745 srcs: [
746 "src/*",
747 "src/e/*",
748 ],
749 }`,
750 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
751 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
752 },
753 {
754 name: "recursive glob",
755 bp: `
756 test {
757 name: "foo",
758 srcs: ["src/**/*"],
759 }`,
760 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
761 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
762 },
763 {
764 name: "filegroup",
765 bp: `
766 test {
767 name: "foo",
768 srcs: [":a"],
769 }`,
770 srcs: []string{"fg/src/a"},
771 rels: []string{"src/a"},
772 },
773 {
774 name: "special characters glob",
775 bp: `
776 test {
777 name: "foo",
778 srcs: ["src_special/*"],
779 }`,
780 srcs: []string{"foo/src_special/$"},
781 rels: []string{"src_special/$"},
782 },
783 }
784
785 buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
786 if err != nil {
787 t.Fatal(err)
788 }
789 defer os.RemoveAll(buildDir)
790
791 for _, test := range tests {
792 t.Run(test.name, func(t *testing.T) {
793 config := TestConfig(buildDir, nil)
794 ctx := NewTestContext()
795
796 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(expandSourcesTestModuleFactory))
797 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
798
799 fgBp := `
800 filegroup {
801 name: "a",
802 srcs: ["src/a"],
803 }
804 `
805
806 mockFS := map[string][]byte{
807 "fg/Android.bp": []byte(fgBp),
808 "foo/Android.bp": []byte(test.bp),
809 "fg/src/a": nil,
810 "foo/src/b": nil,
811 "foo/src/c": nil,
812 "foo/src/d": nil,
813 "foo/src/e/e": nil,
814 "foo/src_special/$": nil,
815 }
816
817 ctx.MockFileSystem(mockFS)
818
819 ctx.Register()
820 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
821 FailIfErrored(t, errs)
822 _, errs = ctx.PrepareBuildActions(config)
823 FailIfErrored(t, errs)
824
825 m := ctx.ModuleForTests("foo", "").Module().(*expandSourcesTestModule)
826
827 if g, w := m.srcs.Strings(), test.srcs; !reflect.DeepEqual(g, w) {
828 t.Errorf("want srcs %q, got %q", w, g)
829 }
830
831 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
832 t.Errorf("want rels %q, got %q", w, g)
833 }
834 })
835 }
836}
837
Colin Cross8854a5a2019-02-11 14:14:16 -0800838func ExampleOutputPath_ReplaceExtension() {
839 ctx := &configErrorWrapper{
840 config: TestConfig("out", nil),
841 }
Colin Cross2cdd5df2019-02-25 10:25:24 -0800842 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -0800843 p2 := p.ReplaceExtension(ctx, "oat")
844 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -0800845 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -0800846
847 // Output:
848 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -0800849 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -0800850}
Colin Cross40e33732019-02-15 11:08:35 -0800851
852func ExampleOutputPath_FileInSameDir() {
853 ctx := &configErrorWrapper{
854 config: TestConfig("out", nil),
855 }
Colin Cross2cdd5df2019-02-25 10:25:24 -0800856 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -0800857 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
858 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -0800859 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -0800860
861 // Output:
862 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -0800863 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -0800864}