blob: b66eb1e912ae5a349e5a29e2d7387ad3417735dd [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
Jaewoong Jung0949f312019-09-11 10:25:18 -0700204 inTestcases bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700205 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 {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700214 return m.baseModuleContext.config
Dan Willemsen00269f22017-07-06 16:59:48 -0700215}
216
217func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
218
219func (m moduleInstallPathContextImpl) InstallInData() bool {
220 return m.inData
221}
222
Jaewoong Jung0949f312019-09-11 10:25:18 -0700223func (m moduleInstallPathContextImpl) InstallInTestcases() bool {
224 return m.inTestcases
225}
226
Dan Willemsen00269f22017-07-06 16:59:48 -0700227func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
228 return m.inSanitizerDir
229}
230
Jiyong Parkf9332f12018-02-01 00:54:12 +0900231func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
232 return m.inRecovery
233}
234
Colin Cross607d8582019-07-29 16:44:46 -0700235func (m moduleInstallPathContextImpl) InstallBypassMake() bool {
236 return false
237}
238
Dan Willemsen00269f22017-07-06 16:59:48 -0700239func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700240 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700241
242 hostTarget := Target{Os: Linux}
243 deviceTarget := Target{Os: Android}
244
245 testCases := []struct {
246 name string
247 ctx *moduleInstallPathContextImpl
248 in []string
249 out string
250 }{
251 {
252 name: "host binary",
253 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700254 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700255 target: hostTarget,
256 },
257 },
258 in: []string{"bin", "my_test"},
259 out: "host/linux-x86/bin/my_test",
260 },
261
262 {
263 name: "system binary",
264 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700265 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700266 target: deviceTarget,
267 },
268 },
269 in: []string{"bin", "my_test"},
270 out: "target/product/test_device/system/bin/my_test",
271 },
272 {
273 name: "vendor binary",
274 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700275 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700276 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900277 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700278 },
279 },
280 in: []string{"bin", "my_test"},
281 out: "target/product/test_device/vendor/bin/my_test",
282 },
Jiyong Park2db76922017-11-08 16:03:48 +0900283 {
284 name: "odm binary",
285 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700286 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900287 target: deviceTarget,
288 kind: deviceSpecificModule,
289 },
290 },
291 in: []string{"bin", "my_test"},
292 out: "target/product/test_device/odm/bin/my_test",
293 },
294 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900295 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900296 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700297 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900298 target: deviceTarget,
299 kind: productSpecificModule,
300 },
301 },
302 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900303 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900304 },
Dario Frenifd05a742018-05-29 13:28:54 +0100305 {
Justin Yund5f6c822019-06-25 16:47:17 +0900306 name: "system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100307 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700308 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100309 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900310 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100311 },
312 },
313 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900314 out: "target/product/test_device/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100315 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700316
317 {
318 name: "system native test binary",
319 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700320 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700321 target: deviceTarget,
322 },
323 inData: true,
324 },
325 in: []string{"nativetest", "my_test"},
326 out: "target/product/test_device/data/nativetest/my_test",
327 },
328 {
329 name: "vendor native test binary",
330 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700331 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700332 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900333 kind: socSpecificModule,
334 },
335 inData: true,
336 },
337 in: []string{"nativetest", "my_test"},
338 out: "target/product/test_device/data/nativetest/my_test",
339 },
340 {
341 name: "odm native test binary",
342 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700343 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900344 target: deviceTarget,
345 kind: deviceSpecificModule,
346 },
347 inData: true,
348 },
349 in: []string{"nativetest", "my_test"},
350 out: "target/product/test_device/data/nativetest/my_test",
351 },
352 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900353 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900354 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700355 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900356 target: deviceTarget,
357 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700358 },
359 inData: true,
360 },
361 in: []string{"nativetest", "my_test"},
362 out: "target/product/test_device/data/nativetest/my_test",
363 },
364
365 {
Justin Yund5f6c822019-06-25 16:47:17 +0900366 name: "system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100367 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700368 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100369 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900370 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100371 },
372 inData: true,
373 },
374 in: []string{"nativetest", "my_test"},
375 out: "target/product/test_device/data/nativetest/my_test",
376 },
377
378 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700379 name: "sanitized system binary",
380 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700381 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700382 target: deviceTarget,
383 },
384 inSanitizerDir: true,
385 },
386 in: []string{"bin", "my_test"},
387 out: "target/product/test_device/data/asan/system/bin/my_test",
388 },
389 {
390 name: "sanitized vendor binary",
391 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700392 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700393 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900394 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700395 },
396 inSanitizerDir: true,
397 },
398 in: []string{"bin", "my_test"},
399 out: "target/product/test_device/data/asan/vendor/bin/my_test",
400 },
Jiyong Park2db76922017-11-08 16:03:48 +0900401 {
402 name: "sanitized odm binary",
403 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700404 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900405 target: deviceTarget,
406 kind: deviceSpecificModule,
407 },
408 inSanitizerDir: true,
409 },
410 in: []string{"bin", "my_test"},
411 out: "target/product/test_device/data/asan/odm/bin/my_test",
412 },
413 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900414 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900415 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700416 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900417 target: deviceTarget,
418 kind: productSpecificModule,
419 },
420 inSanitizerDir: true,
421 },
422 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900423 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900424 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700425
426 {
Justin Yund5f6c822019-06-25 16:47:17 +0900427 name: "sanitized system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100428 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700429 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100430 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900431 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100432 },
433 inSanitizerDir: true,
434 },
435 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900436 out: "target/product/test_device/data/asan/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100437 },
438
439 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700440 name: "sanitized system native test binary",
441 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700442 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700443 target: deviceTarget,
444 },
445 inData: true,
446 inSanitizerDir: true,
447 },
448 in: []string{"nativetest", "my_test"},
449 out: "target/product/test_device/data/asan/data/nativetest/my_test",
450 },
451 {
452 name: "sanitized vendor native test binary",
453 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700454 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700455 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900456 kind: socSpecificModule,
457 },
458 inData: true,
459 inSanitizerDir: true,
460 },
461 in: []string{"nativetest", "my_test"},
462 out: "target/product/test_device/data/asan/data/nativetest/my_test",
463 },
464 {
465 name: "sanitized odm native test binary",
466 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700467 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900468 target: deviceTarget,
469 kind: deviceSpecificModule,
470 },
471 inData: true,
472 inSanitizerDir: true,
473 },
474 in: []string{"nativetest", "my_test"},
475 out: "target/product/test_device/data/asan/data/nativetest/my_test",
476 },
477 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900478 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900479 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700480 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900481 target: deviceTarget,
482 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700483 },
484 inData: true,
485 inSanitizerDir: true,
486 },
487 in: []string{"nativetest", "my_test"},
488 out: "target/product/test_device/data/asan/data/nativetest/my_test",
489 },
Dario Frenifd05a742018-05-29 13:28:54 +0100490 {
Justin Yund5f6c822019-06-25 16:47:17 +0900491 name: "sanitized system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100492 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700493 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100494 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900495 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100496 },
497 inData: true,
498 inSanitizerDir: true,
499 },
500 in: []string{"nativetest", "my_test"},
501 out: "target/product/test_device/data/asan/data/nativetest/my_test",
502 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700503 }
504
505 for _, tc := range testCases {
506 t.Run(tc.name, func(t *testing.T) {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700507 tc.ctx.baseModuleContext.config = testConfig
Dan Willemsen00269f22017-07-06 16:59:48 -0700508 output := PathForModuleInstall(tc.ctx, tc.in...)
509 if output.basePath.path != tc.out {
510 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
511 output.basePath.path,
512 tc.out)
513 }
514 })
515 }
516}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700517
518func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800519 config := TestConfig("out", nil)
520
521 ctx := PathContextForTesting(config, map[string][]byte{
522 "a.txt": nil,
523 "a/txt": nil,
524 "a/b/c": nil,
525 "a/b/d": nil,
526 "b": nil,
527 "b/b.txt": nil,
528 "a/a.txt": nil,
529 })
530
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700531 makePaths := func() Paths {
532 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800533 PathForSource(ctx, "a.txt"),
534 PathForSource(ctx, "a/txt"),
535 PathForSource(ctx, "a/b/c"),
536 PathForSource(ctx, "a/b/d"),
537 PathForSource(ctx, "b"),
538 PathForSource(ctx, "b/b.txt"),
539 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700540 }
541 }
542
543 expected := []string{
544 "a.txt",
545 "a/a.txt",
546 "a/b/c",
547 "a/b/d",
548 "a/txt",
549 "b",
550 "b/b.txt",
551 }
552
553 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700554 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700555
556 sortedPaths := PathsToDirectorySortedPaths(paths)
557 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
558
559 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
560 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
561 }
562
563 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
564 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
565 }
566
567 expectedA := []string{
568 "a/a.txt",
569 "a/b/c",
570 "a/b/d",
571 "a/txt",
572 }
573
574 inA := sortedPaths.PathsInDirectory("a")
575 if !reflect.DeepEqual(inA.Strings(), expectedA) {
576 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
577 }
578
579 expectedA_B := []string{
580 "a/b/c",
581 "a/b/d",
582 }
583
584 inA_B := sortedPaths.PathsInDirectory("a/b")
585 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
586 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
587 }
588
589 expectedB := []string{
590 "b/b.txt",
591 }
592
593 inB := sortedPaths.PathsInDirectory("b")
594 if !reflect.DeepEqual(inB.Strings(), expectedB) {
595 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
596 }
597}
Colin Cross43f08db2018-11-12 10:13:39 -0800598
599func TestMaybeRel(t *testing.T) {
600 testCases := []struct {
601 name string
602 base string
603 target string
604 out string
605 isRel bool
606 }{
607 {
608 name: "normal",
609 base: "a/b/c",
610 target: "a/b/c/d",
611 out: "d",
612 isRel: true,
613 },
614 {
615 name: "parent",
616 base: "a/b/c/d",
617 target: "a/b/c",
618 isRel: false,
619 },
620 {
621 name: "not relative",
622 base: "a/b",
623 target: "c/d",
624 isRel: false,
625 },
626 {
627 name: "abs1",
628 base: "/a",
629 target: "a",
630 isRel: false,
631 },
632 {
633 name: "abs2",
634 base: "a",
635 target: "/a",
636 isRel: false,
637 },
638 }
639
640 for _, testCase := range testCases {
641 t.Run(testCase.name, func(t *testing.T) {
642 ctx := &configErrorWrapper{}
643 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
644 if len(ctx.errors) > 0 {
645 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
646 testCase.base, testCase.target, ctx.errors)
647 }
648 if isRel != testCase.isRel || out != testCase.out {
649 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
650 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
651 }
652 })
653 }
654}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800655
656func TestPathForSource(t *testing.T) {
657 testCases := []struct {
658 name string
659 buildDir string
660 src string
661 err string
662 }{
663 {
664 name: "normal",
665 buildDir: "out",
666 src: "a/b/c",
667 },
668 {
669 name: "abs",
670 buildDir: "out",
671 src: "/a/b/c",
672 err: "is outside directory",
673 },
674 {
675 name: "in out dir",
676 buildDir: "out",
677 src: "out/a/b/c",
678 err: "is in output",
679 },
680 }
681
682 funcs := []struct {
683 name string
684 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
685 }{
686 {"pathForSource", pathForSource},
687 {"safePathForSource", safePathForSource},
688 }
689
690 for _, f := range funcs {
691 t.Run(f.name, func(t *testing.T) {
692 for _, test := range testCases {
693 t.Run(test.name, func(t *testing.T) {
694 testConfig := TestConfig(test.buildDir, nil)
695 ctx := &configErrorWrapper{config: testConfig}
696 _, err := f.f(ctx, test.src)
697 if len(ctx.errors) > 0 {
698 t.Fatalf("unexpected errors %v", ctx.errors)
699 }
700 if err != nil {
701 if test.err == "" {
702 t.Fatalf("unexpected error %q", err.Error())
703 } else if !strings.Contains(err.Error(), test.err) {
704 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
705 }
706 } else {
707 if test.err != "" {
708 t.Fatalf("missing error %q", test.err)
709 }
710 }
711 })
712 }
713 })
714 }
715}
Colin Cross8854a5a2019-02-11 14:14:16 -0800716
Colin Cross8a497952019-03-05 22:25:09 -0800717type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800718 ModuleBase
719 props struct {
720 Srcs []string `android:"path"`
721 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800722
723 Src *string `android:"path"`
Colin Crossba71a3f2019-03-18 12:12:48 -0700724
725 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800726 }
727
Colin Cross8a497952019-03-05 22:25:09 -0800728 src string
729 rel string
730
731 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800732 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800733
734 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800735}
736
Colin Cross8a497952019-03-05 22:25:09 -0800737func pathForModuleSrcTestModuleFactory() Module {
738 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800739 module.AddProperties(&module.props)
740 InitAndroidModule(module)
741 return module
742}
743
Colin Cross8a497952019-03-05 22:25:09 -0800744func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossba71a3f2019-03-18 12:12:48 -0700745 var srcs Paths
746 if p.props.Module_handles_missing_deps {
747 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
748 } else {
749 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
750 }
Colin Cross8a497952019-03-05 22:25:09 -0800751 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800752
Colin Cross8a497952019-03-05 22:25:09 -0800753 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800754 p.rels = append(p.rels, src.Rel())
755 }
Colin Cross8a497952019-03-05 22:25:09 -0800756
757 if p.props.Src != nil {
758 src := PathForModuleSrc(ctx, *p.props.Src)
759 if src != nil {
760 p.src = src.String()
761 p.rel = src.Rel()
762 }
763 }
764
Colin Crossba71a3f2019-03-18 12:12:48 -0700765 if !p.props.Module_handles_missing_deps {
766 p.missingDeps = ctx.GetMissingDependencies()
767 }
Colin Cross6c4f21f2019-06-06 15:41:36 -0700768
769 ctx.Build(pctx, BuildParams{
770 Rule: Touch,
771 Output: PathForModuleOut(ctx, "output"),
772 })
Colin Cross8a497952019-03-05 22:25:09 -0800773}
774
Colin Cross41955e82019-05-29 14:40:35 -0700775type pathForModuleSrcOutputFileProviderModule struct {
776 ModuleBase
777 props struct {
778 Outs []string
779 Tagged []string
780 }
781
782 outs Paths
783 tagged Paths
784}
785
786func pathForModuleSrcOutputFileProviderModuleFactory() Module {
787 module := &pathForModuleSrcOutputFileProviderModule{}
788 module.AddProperties(&module.props)
789 InitAndroidModule(module)
790 return module
791}
792
793func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
794 for _, out := range p.props.Outs {
795 p.outs = append(p.outs, PathForModuleOut(ctx, out))
796 }
797
798 for _, tagged := range p.props.Tagged {
799 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
800 }
801}
802
803func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
804 switch tag {
805 case "":
806 return p.outs, nil
807 case ".tagged":
808 return p.tagged, nil
809 default:
810 return nil, fmt.Errorf("unsupported tag %q", tag)
811 }
812}
813
Colin Cross8a497952019-03-05 22:25:09 -0800814type pathForModuleSrcTestCase struct {
815 name string
816 bp string
817 srcs []string
818 rels []string
819 src string
820 rel string
821}
822
823func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
824 for _, test := range tests {
825 t.Run(test.name, func(t *testing.T) {
826 config := TestConfig(buildDir, nil)
827 ctx := NewTestContext()
828
829 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
Colin Cross41955e82019-05-29 14:40:35 -0700830 ctx.RegisterModuleType("output_file_provider", ModuleFactoryAdaptor(pathForModuleSrcOutputFileProviderModuleFactory))
Colin Cross8a497952019-03-05 22:25:09 -0800831 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
832
833 fgBp := `
834 filegroup {
835 name: "a",
836 srcs: ["src/a"],
837 }
838 `
839
Colin Cross41955e82019-05-29 14:40:35 -0700840 ofpBp := `
841 output_file_provider {
842 name: "b",
843 outs: ["gen/b"],
844 tagged: ["gen/c"],
845 }
846 `
847
Colin Cross8a497952019-03-05 22:25:09 -0800848 mockFS := map[string][]byte{
849 "fg/Android.bp": []byte(fgBp),
850 "foo/Android.bp": []byte(test.bp),
Colin Cross41955e82019-05-29 14:40:35 -0700851 "ofp/Android.bp": []byte(ofpBp),
Colin Cross8a497952019-03-05 22:25:09 -0800852 "fg/src/a": nil,
853 "foo/src/b": nil,
854 "foo/src/c": nil,
855 "foo/src/d": nil,
856 "foo/src/e/e": nil,
857 "foo/src_special/$": nil,
858 }
859
860 ctx.MockFileSystem(mockFS)
861
862 ctx.Register()
Colin Cross41955e82019-05-29 14:40:35 -0700863 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
Colin Cross8a497952019-03-05 22:25:09 -0800864 FailIfErrored(t, errs)
865 _, errs = ctx.PrepareBuildActions(config)
866 FailIfErrored(t, errs)
867
868 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
869
870 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
871 t.Errorf("want srcs %q, got %q", w, g)
872 }
873
874 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
875 t.Errorf("want rels %q, got %q", w, g)
876 }
877
878 if g, w := m.src, test.src; g != w {
879 t.Errorf("want src %q, got %q", w, g)
880 }
881
882 if g, w := m.rel, test.rel; g != w {
883 t.Errorf("want rel %q, got %q", w, g)
884 }
885 })
886 }
Colin Cross937664a2019-03-06 10:17:32 -0800887}
888
Colin Cross8a497952019-03-05 22:25:09 -0800889func TestPathsForModuleSrc(t *testing.T) {
890 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800891 {
892 name: "path",
893 bp: `
894 test {
895 name: "foo",
896 srcs: ["src/b"],
897 }`,
898 srcs: []string{"foo/src/b"},
899 rels: []string{"src/b"},
900 },
901 {
902 name: "glob",
903 bp: `
904 test {
905 name: "foo",
906 srcs: [
907 "src/*",
908 "src/e/*",
909 ],
910 }`,
911 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
912 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
913 },
914 {
915 name: "recursive glob",
916 bp: `
917 test {
918 name: "foo",
919 srcs: ["src/**/*"],
920 }`,
921 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
922 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
923 },
924 {
925 name: "filegroup",
926 bp: `
927 test {
928 name: "foo",
929 srcs: [":a"],
930 }`,
931 srcs: []string{"fg/src/a"},
932 rels: []string{"src/a"},
933 },
934 {
Colin Cross41955e82019-05-29 14:40:35 -0700935 name: "output file provider",
936 bp: `
937 test {
938 name: "foo",
939 srcs: [":b"],
940 }`,
941 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
942 rels: []string{"gen/b"},
943 },
944 {
945 name: "output file provider tagged",
946 bp: `
947 test {
948 name: "foo",
949 srcs: [":b{.tagged}"],
950 }`,
951 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
952 rels: []string{"gen/c"},
953 },
954 {
Colin Cross937664a2019-03-06 10:17:32 -0800955 name: "special characters glob",
956 bp: `
957 test {
958 name: "foo",
959 srcs: ["src_special/*"],
960 }`,
961 srcs: []string{"foo/src_special/$"},
962 rels: []string{"src_special/$"},
963 },
964 }
965
Colin Cross41955e82019-05-29 14:40:35 -0700966 testPathForModuleSrc(t, buildDir, tests)
967}
968
969func TestPathForModuleSrc(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -0800970 tests := []pathForModuleSrcTestCase{
971 {
972 name: "path",
973 bp: `
974 test {
975 name: "foo",
976 src: "src/b",
977 }`,
978 src: "foo/src/b",
979 rel: "src/b",
980 },
981 {
982 name: "glob",
983 bp: `
984 test {
985 name: "foo",
986 src: "src/e/*",
987 }`,
988 src: "foo/src/e/e",
989 rel: "src/e/e",
990 },
991 {
992 name: "filegroup",
993 bp: `
994 test {
995 name: "foo",
996 src: ":a",
997 }`,
998 src: "fg/src/a",
999 rel: "src/a",
1000 },
1001 {
Colin Cross41955e82019-05-29 14:40:35 -07001002 name: "output file provider",
1003 bp: `
1004 test {
1005 name: "foo",
1006 src: ":b",
1007 }`,
1008 src: buildDir + "/.intermediates/ofp/b/gen/b",
1009 rel: "gen/b",
1010 },
1011 {
1012 name: "output file provider tagged",
1013 bp: `
1014 test {
1015 name: "foo",
1016 src: ":b{.tagged}",
1017 }`,
1018 src: buildDir + "/.intermediates/ofp/b/gen/c",
1019 rel: "gen/c",
1020 },
1021 {
Colin Cross8a497952019-03-05 22:25:09 -08001022 name: "special characters glob",
1023 bp: `
1024 test {
1025 name: "foo",
1026 src: "src_special/*",
1027 }`,
1028 src: "foo/src_special/$",
1029 rel: "src_special/$",
1030 },
1031 }
1032
Colin Cross8a497952019-03-05 22:25:09 -08001033 testPathForModuleSrc(t, buildDir, tests)
1034}
Colin Cross937664a2019-03-06 10:17:32 -08001035
Colin Cross8a497952019-03-05 22:25:09 -08001036func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -08001037 config := TestConfig(buildDir, nil)
1038 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
1039
1040 ctx := NewTestContext()
1041 ctx.SetAllowMissingDependencies(true)
1042
1043 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
1044
1045 bp := `
1046 test {
1047 name: "foo",
1048 srcs: [":a"],
1049 exclude_srcs: [":b"],
1050 src: ":c",
1051 }
Colin Crossba71a3f2019-03-18 12:12:48 -07001052
1053 test {
1054 name: "bar",
1055 srcs: [":d"],
1056 exclude_srcs: [":e"],
1057 module_handles_missing_deps: true,
1058 }
Colin Cross8a497952019-03-05 22:25:09 -08001059 `
1060
1061 mockFS := map[string][]byte{
1062 "Android.bp": []byte(bp),
1063 }
1064
1065 ctx.MockFileSystem(mockFS)
1066
1067 ctx.Register()
1068 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
1069 FailIfErrored(t, errs)
1070 _, errs = ctx.PrepareBuildActions(config)
1071 FailIfErrored(t, errs)
1072
1073 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
1074
1075 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001076 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001077 }
1078
1079 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001080 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001081 }
1082
1083 if g, w := foo.src, ""; g != w {
Colin Crossba71a3f2019-03-18 12:12:48 -07001084 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001085 }
1086
Colin Crossba71a3f2019-03-18 12:12:48 -07001087 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1088
1089 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1090 t.Errorf("want bar missing deps %q, got %q", w, g)
1091 }
1092
1093 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1094 t.Errorf("want bar srcs %q, got %q", w, g)
1095 }
Colin Cross937664a2019-03-06 10:17:32 -08001096}
1097
Colin Cross8854a5a2019-02-11 14:14:16 -08001098func ExampleOutputPath_ReplaceExtension() {
1099 ctx := &configErrorWrapper{
1100 config: TestConfig("out", nil),
1101 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001102 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -08001103 p2 := p.ReplaceExtension(ctx, "oat")
1104 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001105 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -08001106
1107 // Output:
1108 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -08001109 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -08001110}
Colin Cross40e33732019-02-15 11:08:35 -08001111
1112func ExampleOutputPath_FileInSameDir() {
1113 ctx := &configErrorWrapper{
1114 config: TestConfig("out", nil),
1115 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001116 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001117 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1118 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001119 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001120
1121 // Output:
1122 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001123 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001124}