blob: 1d8afa9c1bcbfbfdfa54ca9a6f35ad0501139f6b [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
Colin Cross90ba5f42019-10-02 11:10:58 -0700207 inRoot bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700208}
209
210func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
211 return pathtools.MockFs(nil)
212}
213
Colin Crossaabf6792017-11-29 00:27:14 -0800214func (m moduleInstallPathContextImpl) Config() Config {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700215 return m.baseModuleContext.config
Dan Willemsen00269f22017-07-06 16:59:48 -0700216}
217
218func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
219
220func (m moduleInstallPathContextImpl) InstallInData() bool {
221 return m.inData
222}
223
Jaewoong Jung0949f312019-09-11 10:25:18 -0700224func (m moduleInstallPathContextImpl) InstallInTestcases() bool {
225 return m.inTestcases
226}
227
Dan Willemsen00269f22017-07-06 16:59:48 -0700228func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
229 return m.inSanitizerDir
230}
231
Jiyong Parkf9332f12018-02-01 00:54:12 +0900232func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
233 return m.inRecovery
234}
235
Colin Cross90ba5f42019-10-02 11:10:58 -0700236func (m moduleInstallPathContextImpl) InstallInRoot() bool {
237 return m.inRoot
238}
239
Colin Cross607d8582019-07-29 16:44:46 -0700240func (m moduleInstallPathContextImpl) InstallBypassMake() bool {
241 return false
242}
243
Dan Willemsen00269f22017-07-06 16:59:48 -0700244func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700245 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700246
247 hostTarget := Target{Os: Linux}
248 deviceTarget := Target{Os: Android}
249
250 testCases := []struct {
251 name string
252 ctx *moduleInstallPathContextImpl
253 in []string
254 out string
255 }{
256 {
257 name: "host binary",
258 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700259 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700260 target: hostTarget,
261 },
262 },
263 in: []string{"bin", "my_test"},
264 out: "host/linux-x86/bin/my_test",
265 },
266
267 {
268 name: "system binary",
269 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700270 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700271 target: deviceTarget,
272 },
273 },
274 in: []string{"bin", "my_test"},
275 out: "target/product/test_device/system/bin/my_test",
276 },
277 {
278 name: "vendor binary",
279 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700280 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700281 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900282 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700283 },
284 },
285 in: []string{"bin", "my_test"},
286 out: "target/product/test_device/vendor/bin/my_test",
287 },
Jiyong Park2db76922017-11-08 16:03:48 +0900288 {
289 name: "odm binary",
290 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700291 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900292 target: deviceTarget,
293 kind: deviceSpecificModule,
294 },
295 },
296 in: []string{"bin", "my_test"},
297 out: "target/product/test_device/odm/bin/my_test",
298 },
299 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900300 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900301 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700302 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900303 target: deviceTarget,
304 kind: productSpecificModule,
305 },
306 },
307 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900308 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900309 },
Dario Frenifd05a742018-05-29 13:28:54 +0100310 {
Justin Yund5f6c822019-06-25 16:47:17 +0900311 name: "system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100312 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700313 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100314 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900315 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100316 },
317 },
318 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900319 out: "target/product/test_device/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100320 },
Colin Cross90ba5f42019-10-02 11:10:58 -0700321 {
322 name: "root binary",
323 ctx: &moduleInstallPathContextImpl{
324 baseModuleContext: baseModuleContext{
325 target: deviceTarget,
326 },
327 inRoot: true,
328 },
329 in: []string{"my_test"},
330 out: "target/product/test_device/root/my_test",
331 },
332 {
333 name: "recovery binary",
334 ctx: &moduleInstallPathContextImpl{
335 baseModuleContext: baseModuleContext{
336 target: deviceTarget,
337 },
338 inRecovery: true,
339 },
340 in: []string{"bin/my_test"},
341 out: "target/product/test_device/recovery/root/system/bin/my_test",
342 },
343 {
344 name: "recovery root binary",
345 ctx: &moduleInstallPathContextImpl{
346 baseModuleContext: baseModuleContext{
347 target: deviceTarget,
348 },
349 inRecovery: true,
350 inRoot: true,
351 },
352 in: []string{"my_test"},
353 out: "target/product/test_device/recovery/root/my_test",
354 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700355
356 {
357 name: "system native test binary",
358 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700359 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700360 target: deviceTarget,
361 },
362 inData: true,
363 },
364 in: []string{"nativetest", "my_test"},
365 out: "target/product/test_device/data/nativetest/my_test",
366 },
367 {
368 name: "vendor native test binary",
369 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700370 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700371 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900372 kind: socSpecificModule,
373 },
374 inData: true,
375 },
376 in: []string{"nativetest", "my_test"},
377 out: "target/product/test_device/data/nativetest/my_test",
378 },
379 {
380 name: "odm native test binary",
381 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700382 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900383 target: deviceTarget,
384 kind: deviceSpecificModule,
385 },
386 inData: true,
387 },
388 in: []string{"nativetest", "my_test"},
389 out: "target/product/test_device/data/nativetest/my_test",
390 },
391 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900392 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900393 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700394 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900395 target: deviceTarget,
396 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700397 },
398 inData: true,
399 },
400 in: []string{"nativetest", "my_test"},
401 out: "target/product/test_device/data/nativetest/my_test",
402 },
403
404 {
Justin Yund5f6c822019-06-25 16:47:17 +0900405 name: "system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100406 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700407 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100408 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900409 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100410 },
411 inData: true,
412 },
413 in: []string{"nativetest", "my_test"},
414 out: "target/product/test_device/data/nativetest/my_test",
415 },
416
417 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700418 name: "sanitized system binary",
419 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700420 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700421 target: deviceTarget,
422 },
423 inSanitizerDir: true,
424 },
425 in: []string{"bin", "my_test"},
426 out: "target/product/test_device/data/asan/system/bin/my_test",
427 },
428 {
429 name: "sanitized vendor binary",
430 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700431 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700432 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900433 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700434 },
435 inSanitizerDir: true,
436 },
437 in: []string{"bin", "my_test"},
438 out: "target/product/test_device/data/asan/vendor/bin/my_test",
439 },
Jiyong Park2db76922017-11-08 16:03:48 +0900440 {
441 name: "sanitized odm binary",
442 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700443 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900444 target: deviceTarget,
445 kind: deviceSpecificModule,
446 },
447 inSanitizerDir: true,
448 },
449 in: []string{"bin", "my_test"},
450 out: "target/product/test_device/data/asan/odm/bin/my_test",
451 },
452 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900453 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900454 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700455 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900456 target: deviceTarget,
457 kind: productSpecificModule,
458 },
459 inSanitizerDir: true,
460 },
461 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900462 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900463 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700464
465 {
Justin Yund5f6c822019-06-25 16:47:17 +0900466 name: "sanitized system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100467 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700468 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100469 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900470 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100471 },
472 inSanitizerDir: true,
473 },
474 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900475 out: "target/product/test_device/data/asan/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100476 },
477
478 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700479 name: "sanitized system native test binary",
480 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700481 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700482 target: deviceTarget,
483 },
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 },
490 {
491 name: "sanitized vendor native test binary",
492 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700493 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700494 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900495 kind: socSpecificModule,
496 },
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 },
503 {
504 name: "sanitized odm native test binary",
505 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700506 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900507 target: deviceTarget,
508 kind: deviceSpecificModule,
509 },
510 inData: true,
511 inSanitizerDir: true,
512 },
513 in: []string{"nativetest", "my_test"},
514 out: "target/product/test_device/data/asan/data/nativetest/my_test",
515 },
516 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900517 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900518 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700519 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900520 target: deviceTarget,
521 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700522 },
523 inData: true,
524 inSanitizerDir: true,
525 },
526 in: []string{"nativetest", "my_test"},
527 out: "target/product/test_device/data/asan/data/nativetest/my_test",
528 },
Dario Frenifd05a742018-05-29 13:28:54 +0100529 {
Justin Yund5f6c822019-06-25 16:47:17 +0900530 name: "sanitized system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100531 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700532 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100533 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900534 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100535 },
536 inData: true,
537 inSanitizerDir: true,
538 },
539 in: []string{"nativetest", "my_test"},
540 out: "target/product/test_device/data/asan/data/nativetest/my_test",
541 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700542 }
543
544 for _, tc := range testCases {
545 t.Run(tc.name, func(t *testing.T) {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700546 tc.ctx.baseModuleContext.config = testConfig
Dan Willemsen00269f22017-07-06 16:59:48 -0700547 output := PathForModuleInstall(tc.ctx, tc.in...)
548 if output.basePath.path != tc.out {
549 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
550 output.basePath.path,
551 tc.out)
552 }
553 })
554 }
555}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700556
557func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800558 config := TestConfig("out", nil)
559
560 ctx := PathContextForTesting(config, map[string][]byte{
561 "a.txt": nil,
562 "a/txt": nil,
563 "a/b/c": nil,
564 "a/b/d": nil,
565 "b": nil,
566 "b/b.txt": nil,
567 "a/a.txt": nil,
568 })
569
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700570 makePaths := func() Paths {
571 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800572 PathForSource(ctx, "a.txt"),
573 PathForSource(ctx, "a/txt"),
574 PathForSource(ctx, "a/b/c"),
575 PathForSource(ctx, "a/b/d"),
576 PathForSource(ctx, "b"),
577 PathForSource(ctx, "b/b.txt"),
578 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700579 }
580 }
581
582 expected := []string{
583 "a.txt",
584 "a/a.txt",
585 "a/b/c",
586 "a/b/d",
587 "a/txt",
588 "b",
589 "b/b.txt",
590 }
591
592 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700593 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700594
595 sortedPaths := PathsToDirectorySortedPaths(paths)
596 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
597
598 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
599 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
600 }
601
602 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
603 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
604 }
605
606 expectedA := []string{
607 "a/a.txt",
608 "a/b/c",
609 "a/b/d",
610 "a/txt",
611 }
612
613 inA := sortedPaths.PathsInDirectory("a")
614 if !reflect.DeepEqual(inA.Strings(), expectedA) {
615 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
616 }
617
618 expectedA_B := []string{
619 "a/b/c",
620 "a/b/d",
621 }
622
623 inA_B := sortedPaths.PathsInDirectory("a/b")
624 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
625 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
626 }
627
628 expectedB := []string{
629 "b/b.txt",
630 }
631
632 inB := sortedPaths.PathsInDirectory("b")
633 if !reflect.DeepEqual(inB.Strings(), expectedB) {
634 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
635 }
636}
Colin Cross43f08db2018-11-12 10:13:39 -0800637
638func TestMaybeRel(t *testing.T) {
639 testCases := []struct {
640 name string
641 base string
642 target string
643 out string
644 isRel bool
645 }{
646 {
647 name: "normal",
648 base: "a/b/c",
649 target: "a/b/c/d",
650 out: "d",
651 isRel: true,
652 },
653 {
654 name: "parent",
655 base: "a/b/c/d",
656 target: "a/b/c",
657 isRel: false,
658 },
659 {
660 name: "not relative",
661 base: "a/b",
662 target: "c/d",
663 isRel: false,
664 },
665 {
666 name: "abs1",
667 base: "/a",
668 target: "a",
669 isRel: false,
670 },
671 {
672 name: "abs2",
673 base: "a",
674 target: "/a",
675 isRel: false,
676 },
677 }
678
679 for _, testCase := range testCases {
680 t.Run(testCase.name, func(t *testing.T) {
681 ctx := &configErrorWrapper{}
682 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
683 if len(ctx.errors) > 0 {
684 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
685 testCase.base, testCase.target, ctx.errors)
686 }
687 if isRel != testCase.isRel || out != testCase.out {
688 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
689 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
690 }
691 })
692 }
693}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800694
695func TestPathForSource(t *testing.T) {
696 testCases := []struct {
697 name string
698 buildDir string
699 src string
700 err string
701 }{
702 {
703 name: "normal",
704 buildDir: "out",
705 src: "a/b/c",
706 },
707 {
708 name: "abs",
709 buildDir: "out",
710 src: "/a/b/c",
711 err: "is outside directory",
712 },
713 {
714 name: "in out dir",
715 buildDir: "out",
716 src: "out/a/b/c",
717 err: "is in output",
718 },
719 }
720
721 funcs := []struct {
722 name string
723 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
724 }{
725 {"pathForSource", pathForSource},
726 {"safePathForSource", safePathForSource},
727 }
728
729 for _, f := range funcs {
730 t.Run(f.name, func(t *testing.T) {
731 for _, test := range testCases {
732 t.Run(test.name, func(t *testing.T) {
733 testConfig := TestConfig(test.buildDir, nil)
734 ctx := &configErrorWrapper{config: testConfig}
735 _, err := f.f(ctx, test.src)
736 if len(ctx.errors) > 0 {
737 t.Fatalf("unexpected errors %v", ctx.errors)
738 }
739 if err != nil {
740 if test.err == "" {
741 t.Fatalf("unexpected error %q", err.Error())
742 } else if !strings.Contains(err.Error(), test.err) {
743 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
744 }
745 } else {
746 if test.err != "" {
747 t.Fatalf("missing error %q", test.err)
748 }
749 }
750 })
751 }
752 })
753 }
754}
Colin Cross8854a5a2019-02-11 14:14:16 -0800755
Colin Cross8a497952019-03-05 22:25:09 -0800756type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800757 ModuleBase
758 props struct {
759 Srcs []string `android:"path"`
760 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800761
762 Src *string `android:"path"`
Colin Crossba71a3f2019-03-18 12:12:48 -0700763
764 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800765 }
766
Colin Cross8a497952019-03-05 22:25:09 -0800767 src string
768 rel string
769
770 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800771 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800772
773 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800774}
775
Colin Cross8a497952019-03-05 22:25:09 -0800776func pathForModuleSrcTestModuleFactory() Module {
777 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800778 module.AddProperties(&module.props)
779 InitAndroidModule(module)
780 return module
781}
782
Colin Cross8a497952019-03-05 22:25:09 -0800783func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossba71a3f2019-03-18 12:12:48 -0700784 var srcs Paths
785 if p.props.Module_handles_missing_deps {
786 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
787 } else {
788 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
789 }
Colin Cross8a497952019-03-05 22:25:09 -0800790 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800791
Colin Cross8a497952019-03-05 22:25:09 -0800792 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800793 p.rels = append(p.rels, src.Rel())
794 }
Colin Cross8a497952019-03-05 22:25:09 -0800795
796 if p.props.Src != nil {
797 src := PathForModuleSrc(ctx, *p.props.Src)
798 if src != nil {
799 p.src = src.String()
800 p.rel = src.Rel()
801 }
802 }
803
Colin Crossba71a3f2019-03-18 12:12:48 -0700804 if !p.props.Module_handles_missing_deps {
805 p.missingDeps = ctx.GetMissingDependencies()
806 }
Colin Cross6c4f21f2019-06-06 15:41:36 -0700807
808 ctx.Build(pctx, BuildParams{
809 Rule: Touch,
810 Output: PathForModuleOut(ctx, "output"),
811 })
Colin Cross8a497952019-03-05 22:25:09 -0800812}
813
Colin Cross41955e82019-05-29 14:40:35 -0700814type pathForModuleSrcOutputFileProviderModule struct {
815 ModuleBase
816 props struct {
817 Outs []string
818 Tagged []string
819 }
820
821 outs Paths
822 tagged Paths
823}
824
825func pathForModuleSrcOutputFileProviderModuleFactory() Module {
826 module := &pathForModuleSrcOutputFileProviderModule{}
827 module.AddProperties(&module.props)
828 InitAndroidModule(module)
829 return module
830}
831
832func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
833 for _, out := range p.props.Outs {
834 p.outs = append(p.outs, PathForModuleOut(ctx, out))
835 }
836
837 for _, tagged := range p.props.Tagged {
838 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
839 }
840}
841
842func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
843 switch tag {
844 case "":
845 return p.outs, nil
846 case ".tagged":
847 return p.tagged, nil
848 default:
849 return nil, fmt.Errorf("unsupported tag %q", tag)
850 }
851}
852
Colin Cross8a497952019-03-05 22:25:09 -0800853type pathForModuleSrcTestCase struct {
854 name string
855 bp string
856 srcs []string
857 rels []string
858 src string
859 rel string
860}
861
862func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
863 for _, test := range tests {
864 t.Run(test.name, func(t *testing.T) {
865 config := TestConfig(buildDir, nil)
866 ctx := NewTestContext()
867
Colin Cross4b49b762019-11-22 15:25:03 -0800868 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory)
869 ctx.RegisterModuleType("output_file_provider", pathForModuleSrcOutputFileProviderModuleFactory)
870 ctx.RegisterModuleType("filegroup", FileGroupFactory)
Colin Cross8a497952019-03-05 22:25:09 -0800871
872 fgBp := `
873 filegroup {
874 name: "a",
875 srcs: ["src/a"],
876 }
877 `
878
Colin Cross41955e82019-05-29 14:40:35 -0700879 ofpBp := `
880 output_file_provider {
881 name: "b",
882 outs: ["gen/b"],
883 tagged: ["gen/c"],
884 }
885 `
886
Colin Cross8a497952019-03-05 22:25:09 -0800887 mockFS := map[string][]byte{
888 "fg/Android.bp": []byte(fgBp),
889 "foo/Android.bp": []byte(test.bp),
Colin Cross41955e82019-05-29 14:40:35 -0700890 "ofp/Android.bp": []byte(ofpBp),
Colin Cross8a497952019-03-05 22:25:09 -0800891 "fg/src/a": nil,
892 "foo/src/b": nil,
893 "foo/src/c": nil,
894 "foo/src/d": nil,
895 "foo/src/e/e": nil,
896 "foo/src_special/$": nil,
897 }
898
899 ctx.MockFileSystem(mockFS)
900
901 ctx.Register()
Colin Cross41955e82019-05-29 14:40:35 -0700902 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
Colin Cross8a497952019-03-05 22:25:09 -0800903 FailIfErrored(t, errs)
904 _, errs = ctx.PrepareBuildActions(config)
905 FailIfErrored(t, errs)
906
907 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
908
909 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
910 t.Errorf("want srcs %q, got %q", w, g)
911 }
912
913 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
914 t.Errorf("want rels %q, got %q", w, g)
915 }
916
917 if g, w := m.src, test.src; g != w {
918 t.Errorf("want src %q, got %q", w, g)
919 }
920
921 if g, w := m.rel, test.rel; g != w {
922 t.Errorf("want rel %q, got %q", w, g)
923 }
924 })
925 }
Colin Cross937664a2019-03-06 10:17:32 -0800926}
927
Colin Cross8a497952019-03-05 22:25:09 -0800928func TestPathsForModuleSrc(t *testing.T) {
929 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800930 {
931 name: "path",
932 bp: `
933 test {
934 name: "foo",
935 srcs: ["src/b"],
936 }`,
937 srcs: []string{"foo/src/b"},
938 rels: []string{"src/b"},
939 },
940 {
941 name: "glob",
942 bp: `
943 test {
944 name: "foo",
945 srcs: [
946 "src/*",
947 "src/e/*",
948 ],
949 }`,
950 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
951 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
952 },
953 {
954 name: "recursive glob",
955 bp: `
956 test {
957 name: "foo",
958 srcs: ["src/**/*"],
959 }`,
960 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
961 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
962 },
963 {
964 name: "filegroup",
965 bp: `
966 test {
967 name: "foo",
968 srcs: [":a"],
969 }`,
970 srcs: []string{"fg/src/a"},
971 rels: []string{"src/a"},
972 },
973 {
Colin Cross41955e82019-05-29 14:40:35 -0700974 name: "output file provider",
975 bp: `
976 test {
977 name: "foo",
978 srcs: [":b"],
979 }`,
980 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
981 rels: []string{"gen/b"},
982 },
983 {
984 name: "output file provider tagged",
985 bp: `
986 test {
987 name: "foo",
988 srcs: [":b{.tagged}"],
989 }`,
990 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
991 rels: []string{"gen/c"},
992 },
993 {
Colin Cross937664a2019-03-06 10:17:32 -0800994 name: "special characters glob",
995 bp: `
996 test {
997 name: "foo",
998 srcs: ["src_special/*"],
999 }`,
1000 srcs: []string{"foo/src_special/$"},
1001 rels: []string{"src_special/$"},
1002 },
1003 }
1004
Colin Cross41955e82019-05-29 14:40:35 -07001005 testPathForModuleSrc(t, buildDir, tests)
1006}
1007
1008func TestPathForModuleSrc(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -08001009 tests := []pathForModuleSrcTestCase{
1010 {
1011 name: "path",
1012 bp: `
1013 test {
1014 name: "foo",
1015 src: "src/b",
1016 }`,
1017 src: "foo/src/b",
1018 rel: "src/b",
1019 },
1020 {
1021 name: "glob",
1022 bp: `
1023 test {
1024 name: "foo",
1025 src: "src/e/*",
1026 }`,
1027 src: "foo/src/e/e",
1028 rel: "src/e/e",
1029 },
1030 {
1031 name: "filegroup",
1032 bp: `
1033 test {
1034 name: "foo",
1035 src: ":a",
1036 }`,
1037 src: "fg/src/a",
1038 rel: "src/a",
1039 },
1040 {
Colin Cross41955e82019-05-29 14:40:35 -07001041 name: "output file provider",
1042 bp: `
1043 test {
1044 name: "foo",
1045 src: ":b",
1046 }`,
1047 src: buildDir + "/.intermediates/ofp/b/gen/b",
1048 rel: "gen/b",
1049 },
1050 {
1051 name: "output file provider tagged",
1052 bp: `
1053 test {
1054 name: "foo",
1055 src: ":b{.tagged}",
1056 }`,
1057 src: buildDir + "/.intermediates/ofp/b/gen/c",
1058 rel: "gen/c",
1059 },
1060 {
Colin Cross8a497952019-03-05 22:25:09 -08001061 name: "special characters glob",
1062 bp: `
1063 test {
1064 name: "foo",
1065 src: "src_special/*",
1066 }`,
1067 src: "foo/src_special/$",
1068 rel: "src_special/$",
1069 },
1070 }
1071
Colin Cross8a497952019-03-05 22:25:09 -08001072 testPathForModuleSrc(t, buildDir, tests)
1073}
Colin Cross937664a2019-03-06 10:17:32 -08001074
Colin Cross8a497952019-03-05 22:25:09 -08001075func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -08001076 config := TestConfig(buildDir, nil)
1077 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
1078
1079 ctx := NewTestContext()
1080 ctx.SetAllowMissingDependencies(true)
1081
Colin Cross4b49b762019-11-22 15:25:03 -08001082 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory)
Colin Cross8a497952019-03-05 22:25:09 -08001083
1084 bp := `
1085 test {
1086 name: "foo",
1087 srcs: [":a"],
1088 exclude_srcs: [":b"],
1089 src: ":c",
1090 }
Colin Crossba71a3f2019-03-18 12:12:48 -07001091
1092 test {
1093 name: "bar",
1094 srcs: [":d"],
1095 exclude_srcs: [":e"],
1096 module_handles_missing_deps: true,
1097 }
Colin Cross8a497952019-03-05 22:25:09 -08001098 `
1099
1100 mockFS := map[string][]byte{
1101 "Android.bp": []byte(bp),
1102 }
1103
1104 ctx.MockFileSystem(mockFS)
1105
1106 ctx.Register()
1107 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
1108 FailIfErrored(t, errs)
1109 _, errs = ctx.PrepareBuildActions(config)
1110 FailIfErrored(t, errs)
1111
1112 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
1113
1114 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001115 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001116 }
1117
1118 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001119 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001120 }
1121
1122 if g, w := foo.src, ""; g != w {
Colin Crossba71a3f2019-03-18 12:12:48 -07001123 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001124 }
1125
Colin Crossba71a3f2019-03-18 12:12:48 -07001126 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1127
1128 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1129 t.Errorf("want bar missing deps %q, got %q", w, g)
1130 }
1131
1132 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1133 t.Errorf("want bar srcs %q, got %q", w, g)
1134 }
Colin Cross937664a2019-03-06 10:17:32 -08001135}
1136
Colin Cross8854a5a2019-02-11 14:14:16 -08001137func ExampleOutputPath_ReplaceExtension() {
1138 ctx := &configErrorWrapper{
1139 config: TestConfig("out", nil),
1140 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001141 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -08001142 p2 := p.ReplaceExtension(ctx, "oat")
1143 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001144 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -08001145
1146 // Output:
1147 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -08001148 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -08001149}
Colin Cross40e33732019-02-15 11:08:35 -08001150
1151func ExampleOutputPath_FileInSameDir() {
1152 ctx := &configErrorWrapper{
1153 config: TestConfig("out", nil),
1154 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001155 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001156 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1157 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001158 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001159
1160 // Output:
1161 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001162 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001163}