blob: f2996bff80ff3c9a33f80c8b12dbde6b263516b8 [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"
20 "reflect"
21 "strings"
22 "testing"
Dan Willemsen00269f22017-07-06 16:59:48 -070023
24 "github.com/google/blueprint/pathtools"
Colin Cross8a497952019-03-05 22:25:09 -080025 "github.com/google/blueprint/proptools"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070026)
27
28type strsTestCase struct {
29 in []string
30 out string
31 err []error
32}
33
34var commonValidatePathTestCases = []strsTestCase{
35 {
36 in: []string{""},
37 out: "",
38 },
39 {
40 in: []string{"a/b"},
41 out: "a/b",
42 },
43 {
44 in: []string{"a/b", "c"},
45 out: "a/b/c",
46 },
47 {
48 in: []string{"a/.."},
49 out: ".",
50 },
51 {
52 in: []string{"."},
53 out: ".",
54 },
55 {
56 in: []string{".."},
57 out: "",
58 err: []error{errors.New("Path is outside directory: ..")},
59 },
60 {
61 in: []string{"../a"},
62 out: "",
63 err: []error{errors.New("Path is outside directory: ../a")},
64 },
65 {
66 in: []string{"b/../../a"},
67 out: "",
68 err: []error{errors.New("Path is outside directory: ../a")},
69 },
70 {
71 in: []string{"/a"},
72 out: "",
73 err: []error{errors.New("Path is outside directory: /a")},
74 },
Dan Willemsen80a7c2a2015-12-21 14:57:11 -080075 {
76 in: []string{"a", "../b"},
77 out: "",
78 err: []error{errors.New("Path is outside directory: ../b")},
79 },
80 {
81 in: []string{"a", "b/../../c"},
82 out: "",
83 err: []error{errors.New("Path is outside directory: ../c")},
84 },
85 {
86 in: []string{"a", "./.."},
87 out: "",
88 err: []error{errors.New("Path is outside directory: ..")},
89 },
Dan Willemsen34cc69e2015-09-23 15:26:20 -070090}
91
92var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
93 {
94 in: []string{"$host/../$a"},
95 out: "$a",
96 },
97}...)
98
99var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
100 {
101 in: []string{"$host/../$a"},
102 out: "",
103 err: []error{errors.New("Path contains invalid character($): $host/../$a")},
104 },
105 {
106 in: []string{"$host/.."},
107 out: "",
108 err: []error{errors.New("Path contains invalid character($): $host/..")},
109 },
110}...)
111
112func TestValidateSafePath(t *testing.T) {
113 for _, testCase := range validateSafePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800114 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
115 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800116 out, err := validateSafePath(testCase.in...)
117 if err != nil {
118 reportPathError(ctx, err)
119 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800120 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
121 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700122 }
123}
124
125func TestValidatePath(t *testing.T) {
126 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800127 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
128 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800129 out, err := validatePath(testCase.in...)
130 if err != nil {
131 reportPathError(ctx, err)
132 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800133 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
134 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700135 }
136}
137
138func TestOptionalPath(t *testing.T) {
139 var path OptionalPath
140 checkInvalidOptionalPath(t, path)
141
142 path = OptionalPathForPath(nil)
143 checkInvalidOptionalPath(t, path)
144}
145
146func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800147 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700148 if path.Valid() {
149 t.Errorf("Uninitialized OptionalPath should not be valid")
150 }
151 if path.String() != "" {
152 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
153 }
154 defer func() {
155 if r := recover(); r == nil {
156 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
157 }
158 }()
159 path.Path()
160}
161
162func check(t *testing.T, testType, testString string,
163 got interface{}, err []error,
164 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800165 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700166
167 printedTestCase := false
168 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800169 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700170 if !printedTestCase {
171 t.Errorf("test case %s: %s", testType, testString)
172 printedTestCase = true
173 }
174 t.Errorf("incorrect %s", s)
175 t.Errorf(" expected: %s", p(expected))
176 t.Errorf(" got: %s", p(got))
177 }
178
179 if !reflect.DeepEqual(expectedErr, err) {
180 e("errors:", expectedErr, err)
181 }
182
183 if !reflect.DeepEqual(expected, got) {
184 e("output:", expected, got)
185 }
186}
187
188func p(in interface{}) string {
189 if v, ok := in.([]interface{}); ok {
190 s := make([]string, len(v))
191 for i := range v {
192 s[i] = fmt.Sprintf("%#v", v[i])
193 }
194 return "[" + strings.Join(s, ", ") + "]"
195 } else {
196 return fmt.Sprintf("%#v", in)
197 }
198}
Dan Willemsen00269f22017-07-06 16:59:48 -0700199
200type moduleInstallPathContextImpl struct {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700201 baseModuleContext
Dan Willemsen00269f22017-07-06 16:59:48 -0700202
203 inData bool
204 inSanitizerDir bool
Jiyong Parkf9332f12018-02-01 00:54:12 +0900205 inRecovery bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700206}
207
208func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
209 return pathtools.MockFs(nil)
210}
211
Colin Crossaabf6792017-11-29 00:27:14 -0800212func (m moduleInstallPathContextImpl) Config() Config {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700213 return m.baseModuleContext.config
Dan Willemsen00269f22017-07-06 16:59:48 -0700214}
215
216func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
217
218func (m moduleInstallPathContextImpl) InstallInData() bool {
219 return m.inData
220}
221
222func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
223 return m.inSanitizerDir
224}
225
Jiyong Parkf9332f12018-02-01 00:54:12 +0900226func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
227 return m.inRecovery
228}
229
Colin Cross607d8582019-07-29 16:44:46 -0700230func (m moduleInstallPathContextImpl) InstallBypassMake() bool {
231 return false
232}
233
Dan Willemsen00269f22017-07-06 16:59:48 -0700234func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700235 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700236
237 hostTarget := Target{Os: Linux}
238 deviceTarget := Target{Os: Android}
239
240 testCases := []struct {
241 name string
242 ctx *moduleInstallPathContextImpl
243 in []string
244 out string
245 }{
246 {
247 name: "host binary",
248 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700249 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700250 target: hostTarget,
251 },
252 },
253 in: []string{"bin", "my_test"},
254 out: "host/linux-x86/bin/my_test",
255 },
256
257 {
258 name: "system binary",
259 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700260 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700261 target: deviceTarget,
262 },
263 },
264 in: []string{"bin", "my_test"},
265 out: "target/product/test_device/system/bin/my_test",
266 },
267 {
268 name: "vendor binary",
269 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700270 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700271 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900272 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700273 },
274 },
275 in: []string{"bin", "my_test"},
276 out: "target/product/test_device/vendor/bin/my_test",
277 },
Jiyong Park2db76922017-11-08 16:03:48 +0900278 {
279 name: "odm binary",
280 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700281 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900282 target: deviceTarget,
283 kind: deviceSpecificModule,
284 },
285 },
286 in: []string{"bin", "my_test"},
287 out: "target/product/test_device/odm/bin/my_test",
288 },
289 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900290 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900291 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700292 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900293 target: deviceTarget,
294 kind: productSpecificModule,
295 },
296 },
297 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900298 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900299 },
Dario Frenifd05a742018-05-29 13:28:54 +0100300 {
Justin Yund5f6c822019-06-25 16:47:17 +0900301 name: "system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100302 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700303 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100304 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900305 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100306 },
307 },
308 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900309 out: "target/product/test_device/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100310 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700311
312 {
313 name: "system native test binary",
314 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700315 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700316 target: deviceTarget,
317 },
318 inData: true,
319 },
320 in: []string{"nativetest", "my_test"},
321 out: "target/product/test_device/data/nativetest/my_test",
322 },
323 {
324 name: "vendor native test binary",
325 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700326 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700327 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900328 kind: socSpecificModule,
329 },
330 inData: true,
331 },
332 in: []string{"nativetest", "my_test"},
333 out: "target/product/test_device/data/nativetest/my_test",
334 },
335 {
336 name: "odm native test binary",
337 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700338 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900339 target: deviceTarget,
340 kind: deviceSpecificModule,
341 },
342 inData: true,
343 },
344 in: []string{"nativetest", "my_test"},
345 out: "target/product/test_device/data/nativetest/my_test",
346 },
347 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900348 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900349 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700350 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900351 target: deviceTarget,
352 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700353 },
354 inData: true,
355 },
356 in: []string{"nativetest", "my_test"},
357 out: "target/product/test_device/data/nativetest/my_test",
358 },
359
360 {
Justin Yund5f6c822019-06-25 16:47:17 +0900361 name: "system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100362 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700363 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100364 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900365 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100366 },
367 inData: true,
368 },
369 in: []string{"nativetest", "my_test"},
370 out: "target/product/test_device/data/nativetest/my_test",
371 },
372
373 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700374 name: "sanitized system binary",
375 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700376 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700377 target: deviceTarget,
378 },
379 inSanitizerDir: true,
380 },
381 in: []string{"bin", "my_test"},
382 out: "target/product/test_device/data/asan/system/bin/my_test",
383 },
384 {
385 name: "sanitized vendor binary",
386 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700387 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700388 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900389 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700390 },
391 inSanitizerDir: true,
392 },
393 in: []string{"bin", "my_test"},
394 out: "target/product/test_device/data/asan/vendor/bin/my_test",
395 },
Jiyong Park2db76922017-11-08 16:03:48 +0900396 {
397 name: "sanitized odm binary",
398 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700399 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900400 target: deviceTarget,
401 kind: deviceSpecificModule,
402 },
403 inSanitizerDir: true,
404 },
405 in: []string{"bin", "my_test"},
406 out: "target/product/test_device/data/asan/odm/bin/my_test",
407 },
408 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900409 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900410 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700411 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900412 target: deviceTarget,
413 kind: productSpecificModule,
414 },
415 inSanitizerDir: true,
416 },
417 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900418 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900419 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700420
421 {
Justin Yund5f6c822019-06-25 16:47:17 +0900422 name: "sanitized system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100423 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700424 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100425 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900426 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100427 },
428 inSanitizerDir: true,
429 },
430 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900431 out: "target/product/test_device/data/asan/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100432 },
433
434 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700435 name: "sanitized system native test binary",
436 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700437 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700438 target: deviceTarget,
439 },
440 inData: true,
441 inSanitizerDir: true,
442 },
443 in: []string{"nativetest", "my_test"},
444 out: "target/product/test_device/data/asan/data/nativetest/my_test",
445 },
446 {
447 name: "sanitized vendor native test binary",
448 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700449 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700450 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900451 kind: socSpecificModule,
452 },
453 inData: true,
454 inSanitizerDir: true,
455 },
456 in: []string{"nativetest", "my_test"},
457 out: "target/product/test_device/data/asan/data/nativetest/my_test",
458 },
459 {
460 name: "sanitized odm native test binary",
461 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700462 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900463 target: deviceTarget,
464 kind: deviceSpecificModule,
465 },
466 inData: true,
467 inSanitizerDir: true,
468 },
469 in: []string{"nativetest", "my_test"},
470 out: "target/product/test_device/data/asan/data/nativetest/my_test",
471 },
472 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900473 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900474 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700475 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900476 target: deviceTarget,
477 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700478 },
479 inData: true,
480 inSanitizerDir: true,
481 },
482 in: []string{"nativetest", "my_test"},
483 out: "target/product/test_device/data/asan/data/nativetest/my_test",
484 },
Dario Frenifd05a742018-05-29 13:28:54 +0100485 {
Justin Yund5f6c822019-06-25 16:47:17 +0900486 name: "sanitized system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100487 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700488 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100489 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900490 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100491 },
492 inData: true,
493 inSanitizerDir: true,
494 },
495 in: []string{"nativetest", "my_test"},
496 out: "target/product/test_device/data/asan/data/nativetest/my_test",
497 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700498 }
499
500 for _, tc := range testCases {
501 t.Run(tc.name, func(t *testing.T) {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700502 tc.ctx.baseModuleContext.config = testConfig
Dan Willemsen00269f22017-07-06 16:59:48 -0700503 output := PathForModuleInstall(tc.ctx, tc.in...)
504 if output.basePath.path != tc.out {
505 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
506 output.basePath.path,
507 tc.out)
508 }
509 })
510 }
511}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700512
513func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800514 config := TestConfig("out", nil)
515
516 ctx := PathContextForTesting(config, map[string][]byte{
517 "a.txt": nil,
518 "a/txt": nil,
519 "a/b/c": nil,
520 "a/b/d": nil,
521 "b": nil,
522 "b/b.txt": nil,
523 "a/a.txt": nil,
524 })
525
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700526 makePaths := func() Paths {
527 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800528 PathForSource(ctx, "a.txt"),
529 PathForSource(ctx, "a/txt"),
530 PathForSource(ctx, "a/b/c"),
531 PathForSource(ctx, "a/b/d"),
532 PathForSource(ctx, "b"),
533 PathForSource(ctx, "b/b.txt"),
534 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700535 }
536 }
537
538 expected := []string{
539 "a.txt",
540 "a/a.txt",
541 "a/b/c",
542 "a/b/d",
543 "a/txt",
544 "b",
545 "b/b.txt",
546 }
547
548 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700549 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700550
551 sortedPaths := PathsToDirectorySortedPaths(paths)
552 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
553
554 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
555 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
556 }
557
558 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
559 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
560 }
561
562 expectedA := []string{
563 "a/a.txt",
564 "a/b/c",
565 "a/b/d",
566 "a/txt",
567 }
568
569 inA := sortedPaths.PathsInDirectory("a")
570 if !reflect.DeepEqual(inA.Strings(), expectedA) {
571 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
572 }
573
574 expectedA_B := []string{
575 "a/b/c",
576 "a/b/d",
577 }
578
579 inA_B := sortedPaths.PathsInDirectory("a/b")
580 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
581 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
582 }
583
584 expectedB := []string{
585 "b/b.txt",
586 }
587
588 inB := sortedPaths.PathsInDirectory("b")
589 if !reflect.DeepEqual(inB.Strings(), expectedB) {
590 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
591 }
592}
Colin Cross43f08db2018-11-12 10:13:39 -0800593
594func TestMaybeRel(t *testing.T) {
595 testCases := []struct {
596 name string
597 base string
598 target string
599 out string
600 isRel bool
601 }{
602 {
603 name: "normal",
604 base: "a/b/c",
605 target: "a/b/c/d",
606 out: "d",
607 isRel: true,
608 },
609 {
610 name: "parent",
611 base: "a/b/c/d",
612 target: "a/b/c",
613 isRel: false,
614 },
615 {
616 name: "not relative",
617 base: "a/b",
618 target: "c/d",
619 isRel: false,
620 },
621 {
622 name: "abs1",
623 base: "/a",
624 target: "a",
625 isRel: false,
626 },
627 {
628 name: "abs2",
629 base: "a",
630 target: "/a",
631 isRel: false,
632 },
633 }
634
635 for _, testCase := range testCases {
636 t.Run(testCase.name, func(t *testing.T) {
637 ctx := &configErrorWrapper{}
638 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
639 if len(ctx.errors) > 0 {
640 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
641 testCase.base, testCase.target, ctx.errors)
642 }
643 if isRel != testCase.isRel || out != testCase.out {
644 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
645 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
646 }
647 })
648 }
649}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800650
651func TestPathForSource(t *testing.T) {
652 testCases := []struct {
653 name string
654 buildDir string
655 src string
656 err string
657 }{
658 {
659 name: "normal",
660 buildDir: "out",
661 src: "a/b/c",
662 },
663 {
664 name: "abs",
665 buildDir: "out",
666 src: "/a/b/c",
667 err: "is outside directory",
668 },
669 {
670 name: "in out dir",
671 buildDir: "out",
672 src: "out/a/b/c",
673 err: "is in output",
674 },
675 }
676
677 funcs := []struct {
678 name string
679 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
680 }{
681 {"pathForSource", pathForSource},
682 {"safePathForSource", safePathForSource},
683 }
684
685 for _, f := range funcs {
686 t.Run(f.name, func(t *testing.T) {
687 for _, test := range testCases {
688 t.Run(test.name, func(t *testing.T) {
689 testConfig := TestConfig(test.buildDir, nil)
690 ctx := &configErrorWrapper{config: testConfig}
691 _, err := f.f(ctx, test.src)
692 if len(ctx.errors) > 0 {
693 t.Fatalf("unexpected errors %v", ctx.errors)
694 }
695 if err != nil {
696 if test.err == "" {
697 t.Fatalf("unexpected error %q", err.Error())
698 } else if !strings.Contains(err.Error(), test.err) {
699 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
700 }
701 } else {
702 if test.err != "" {
703 t.Fatalf("missing error %q", test.err)
704 }
705 }
706 })
707 }
708 })
709 }
710}
Colin Cross8854a5a2019-02-11 14:14:16 -0800711
Colin Cross8a497952019-03-05 22:25:09 -0800712type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800713 ModuleBase
714 props struct {
715 Srcs []string `android:"path"`
716 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800717
718 Src *string `android:"path"`
Colin Crossba71a3f2019-03-18 12:12:48 -0700719
720 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800721 }
722
Colin Cross8a497952019-03-05 22:25:09 -0800723 src string
724 rel string
725
726 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800727 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800728
729 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800730}
731
Colin Cross8a497952019-03-05 22:25:09 -0800732func pathForModuleSrcTestModuleFactory() Module {
733 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800734 module.AddProperties(&module.props)
735 InitAndroidModule(module)
736 return module
737}
738
Colin Cross8a497952019-03-05 22:25:09 -0800739func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossba71a3f2019-03-18 12:12:48 -0700740 var srcs Paths
741 if p.props.Module_handles_missing_deps {
742 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
743 } else {
744 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
745 }
Colin Cross8a497952019-03-05 22:25:09 -0800746 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800747
Colin Cross8a497952019-03-05 22:25:09 -0800748 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800749 p.rels = append(p.rels, src.Rel())
750 }
Colin Cross8a497952019-03-05 22:25:09 -0800751
752 if p.props.Src != nil {
753 src := PathForModuleSrc(ctx, *p.props.Src)
754 if src != nil {
755 p.src = src.String()
756 p.rel = src.Rel()
757 }
758 }
759
Colin Crossba71a3f2019-03-18 12:12:48 -0700760 if !p.props.Module_handles_missing_deps {
761 p.missingDeps = ctx.GetMissingDependencies()
762 }
Colin Cross6c4f21f2019-06-06 15:41:36 -0700763
764 ctx.Build(pctx, BuildParams{
765 Rule: Touch,
766 Output: PathForModuleOut(ctx, "output"),
767 })
Colin Cross8a497952019-03-05 22:25:09 -0800768}
769
Colin Cross41955e82019-05-29 14:40:35 -0700770type pathForModuleSrcOutputFileProviderModule struct {
771 ModuleBase
772 props struct {
773 Outs []string
774 Tagged []string
775 }
776
777 outs Paths
778 tagged Paths
779}
780
781func pathForModuleSrcOutputFileProviderModuleFactory() Module {
782 module := &pathForModuleSrcOutputFileProviderModule{}
783 module.AddProperties(&module.props)
784 InitAndroidModule(module)
785 return module
786}
787
788func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
789 for _, out := range p.props.Outs {
790 p.outs = append(p.outs, PathForModuleOut(ctx, out))
791 }
792
793 for _, tagged := range p.props.Tagged {
794 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
795 }
796}
797
798func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
799 switch tag {
800 case "":
801 return p.outs, nil
802 case ".tagged":
803 return p.tagged, nil
804 default:
805 return nil, fmt.Errorf("unsupported tag %q", tag)
806 }
807}
808
Colin Cross8a497952019-03-05 22:25:09 -0800809type pathForModuleSrcTestCase struct {
810 name string
811 bp string
812 srcs []string
813 rels []string
814 src string
815 rel string
816}
817
818func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
819 for _, test := range tests {
820 t.Run(test.name, func(t *testing.T) {
821 config := TestConfig(buildDir, nil)
822 ctx := NewTestContext()
823
824 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
Colin Cross41955e82019-05-29 14:40:35 -0700825 ctx.RegisterModuleType("output_file_provider", ModuleFactoryAdaptor(pathForModuleSrcOutputFileProviderModuleFactory))
Colin Cross8a497952019-03-05 22:25:09 -0800826 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
827
828 fgBp := `
829 filegroup {
830 name: "a",
831 srcs: ["src/a"],
832 }
833 `
834
Colin Cross41955e82019-05-29 14:40:35 -0700835 ofpBp := `
836 output_file_provider {
837 name: "b",
838 outs: ["gen/b"],
839 tagged: ["gen/c"],
840 }
841 `
842
Colin Cross8a497952019-03-05 22:25:09 -0800843 mockFS := map[string][]byte{
844 "fg/Android.bp": []byte(fgBp),
845 "foo/Android.bp": []byte(test.bp),
Colin Cross41955e82019-05-29 14:40:35 -0700846 "ofp/Android.bp": []byte(ofpBp),
Colin Cross8a497952019-03-05 22:25:09 -0800847 "fg/src/a": nil,
848 "foo/src/b": nil,
849 "foo/src/c": nil,
850 "foo/src/d": nil,
851 "foo/src/e/e": nil,
852 "foo/src_special/$": nil,
853 }
854
855 ctx.MockFileSystem(mockFS)
856
857 ctx.Register()
Colin Cross41955e82019-05-29 14:40:35 -0700858 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
Colin Cross8a497952019-03-05 22:25:09 -0800859 FailIfErrored(t, errs)
860 _, errs = ctx.PrepareBuildActions(config)
861 FailIfErrored(t, errs)
862
863 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
864
865 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
866 t.Errorf("want srcs %q, got %q", w, g)
867 }
868
869 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
870 t.Errorf("want rels %q, got %q", w, g)
871 }
872
873 if g, w := m.src, test.src; g != w {
874 t.Errorf("want src %q, got %q", w, g)
875 }
876
877 if g, w := m.rel, test.rel; g != w {
878 t.Errorf("want rel %q, got %q", w, g)
879 }
880 })
881 }
Colin Cross937664a2019-03-06 10:17:32 -0800882}
883
Colin Cross8a497952019-03-05 22:25:09 -0800884func TestPathsForModuleSrc(t *testing.T) {
885 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800886 {
887 name: "path",
888 bp: `
889 test {
890 name: "foo",
891 srcs: ["src/b"],
892 }`,
893 srcs: []string{"foo/src/b"},
894 rels: []string{"src/b"},
895 },
896 {
897 name: "glob",
898 bp: `
899 test {
900 name: "foo",
901 srcs: [
902 "src/*",
903 "src/e/*",
904 ],
905 }`,
906 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
907 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
908 },
909 {
910 name: "recursive glob",
911 bp: `
912 test {
913 name: "foo",
914 srcs: ["src/**/*"],
915 }`,
916 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
917 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
918 },
919 {
920 name: "filegroup",
921 bp: `
922 test {
923 name: "foo",
924 srcs: [":a"],
925 }`,
926 srcs: []string{"fg/src/a"},
927 rels: []string{"src/a"},
928 },
929 {
Colin Cross41955e82019-05-29 14:40:35 -0700930 name: "output file provider",
931 bp: `
932 test {
933 name: "foo",
934 srcs: [":b"],
935 }`,
936 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
937 rels: []string{"gen/b"},
938 },
939 {
940 name: "output file provider tagged",
941 bp: `
942 test {
943 name: "foo",
944 srcs: [":b{.tagged}"],
945 }`,
946 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
947 rels: []string{"gen/c"},
948 },
949 {
Colin Cross937664a2019-03-06 10:17:32 -0800950 name: "special characters glob",
951 bp: `
952 test {
953 name: "foo",
954 srcs: ["src_special/*"],
955 }`,
956 srcs: []string{"foo/src_special/$"},
957 rels: []string{"src_special/$"},
958 },
959 }
960
Colin Cross41955e82019-05-29 14:40:35 -0700961 testPathForModuleSrc(t, buildDir, tests)
962}
963
964func TestPathForModuleSrc(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -0800965 tests := []pathForModuleSrcTestCase{
966 {
967 name: "path",
968 bp: `
969 test {
970 name: "foo",
971 src: "src/b",
972 }`,
973 src: "foo/src/b",
974 rel: "src/b",
975 },
976 {
977 name: "glob",
978 bp: `
979 test {
980 name: "foo",
981 src: "src/e/*",
982 }`,
983 src: "foo/src/e/e",
984 rel: "src/e/e",
985 },
986 {
987 name: "filegroup",
988 bp: `
989 test {
990 name: "foo",
991 src: ":a",
992 }`,
993 src: "fg/src/a",
994 rel: "src/a",
995 },
996 {
Colin Cross41955e82019-05-29 14:40:35 -0700997 name: "output file provider",
998 bp: `
999 test {
1000 name: "foo",
1001 src: ":b",
1002 }`,
1003 src: buildDir + "/.intermediates/ofp/b/gen/b",
1004 rel: "gen/b",
1005 },
1006 {
1007 name: "output file provider tagged",
1008 bp: `
1009 test {
1010 name: "foo",
1011 src: ":b{.tagged}",
1012 }`,
1013 src: buildDir + "/.intermediates/ofp/b/gen/c",
1014 rel: "gen/c",
1015 },
1016 {
Colin Cross8a497952019-03-05 22:25:09 -08001017 name: "special characters glob",
1018 bp: `
1019 test {
1020 name: "foo",
1021 src: "src_special/*",
1022 }`,
1023 src: "foo/src_special/$",
1024 rel: "src_special/$",
1025 },
1026 }
1027
Colin Cross8a497952019-03-05 22:25:09 -08001028 testPathForModuleSrc(t, buildDir, tests)
1029}
Colin Cross937664a2019-03-06 10:17:32 -08001030
Colin Cross8a497952019-03-05 22:25:09 -08001031func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -08001032 config := TestConfig(buildDir, nil)
1033 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
1034
1035 ctx := NewTestContext()
1036 ctx.SetAllowMissingDependencies(true)
1037
1038 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
1039
1040 bp := `
1041 test {
1042 name: "foo",
1043 srcs: [":a"],
1044 exclude_srcs: [":b"],
1045 src: ":c",
1046 }
Colin Crossba71a3f2019-03-18 12:12:48 -07001047
1048 test {
1049 name: "bar",
1050 srcs: [":d"],
1051 exclude_srcs: [":e"],
1052 module_handles_missing_deps: true,
1053 }
Colin Cross8a497952019-03-05 22:25:09 -08001054 `
1055
1056 mockFS := map[string][]byte{
1057 "Android.bp": []byte(bp),
1058 }
1059
1060 ctx.MockFileSystem(mockFS)
1061
1062 ctx.Register()
1063 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
1064 FailIfErrored(t, errs)
1065 _, errs = ctx.PrepareBuildActions(config)
1066 FailIfErrored(t, errs)
1067
1068 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
1069
1070 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001071 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001072 }
1073
1074 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001075 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001076 }
1077
1078 if g, w := foo.src, ""; g != w {
Colin Crossba71a3f2019-03-18 12:12:48 -07001079 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001080 }
1081
Colin Crossba71a3f2019-03-18 12:12:48 -07001082 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1083
1084 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1085 t.Errorf("want bar missing deps %q, got %q", w, g)
1086 }
1087
1088 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1089 t.Errorf("want bar srcs %q, got %q", w, g)
1090 }
Colin Cross937664a2019-03-06 10:17:32 -08001091}
1092
Colin Cross8854a5a2019-02-11 14:14:16 -08001093func ExampleOutputPath_ReplaceExtension() {
1094 ctx := &configErrorWrapper{
1095 config: TestConfig("out", nil),
1096 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001097 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -08001098 p2 := p.ReplaceExtension(ctx, "oat")
1099 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001100 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -08001101
1102 // Output:
1103 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -08001104 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -08001105}
Colin Cross40e33732019-02-15 11:08:35 -08001106
1107func ExampleOutputPath_FileInSameDir() {
1108 ctx := &configErrorWrapper{
1109 config: TestConfig("out", nil),
1110 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001111 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001112 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1113 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001114 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001115
1116 // Output:
1117 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001118 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001119}