blob: 8286e9a3578de60461a3fa7cf4cf62deea086668 [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
Dan Willemsen00269f22017-07-06 16:59:48 -0700230func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700231 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700232
233 hostTarget := Target{Os: Linux}
234 deviceTarget := Target{Os: Android}
235
236 testCases := []struct {
237 name string
238 ctx *moduleInstallPathContextImpl
239 in []string
240 out string
241 }{
242 {
243 name: "host binary",
244 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700245 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700246 target: hostTarget,
247 },
248 },
249 in: []string{"bin", "my_test"},
250 out: "host/linux-x86/bin/my_test",
251 },
252
253 {
254 name: "system binary",
255 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700256 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700257 target: deviceTarget,
258 },
259 },
260 in: []string{"bin", "my_test"},
261 out: "target/product/test_device/system/bin/my_test",
262 },
263 {
264 name: "vendor binary",
265 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700266 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700267 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900268 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700269 },
270 },
271 in: []string{"bin", "my_test"},
272 out: "target/product/test_device/vendor/bin/my_test",
273 },
Jiyong Park2db76922017-11-08 16:03:48 +0900274 {
275 name: "odm binary",
276 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700277 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900278 target: deviceTarget,
279 kind: deviceSpecificModule,
280 },
281 },
282 in: []string{"bin", "my_test"},
283 out: "target/product/test_device/odm/bin/my_test",
284 },
285 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900286 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900287 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700288 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900289 target: deviceTarget,
290 kind: productSpecificModule,
291 },
292 },
293 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900294 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900295 },
Dario Frenifd05a742018-05-29 13:28:54 +0100296 {
Justin Yund5f6c822019-06-25 16:47:17 +0900297 name: "system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100298 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700299 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100300 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900301 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100302 },
303 },
304 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900305 out: "target/product/test_device/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100306 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700307
308 {
309 name: "system native test binary",
310 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700311 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700312 target: deviceTarget,
313 },
314 inData: true,
315 },
316 in: []string{"nativetest", "my_test"},
317 out: "target/product/test_device/data/nativetest/my_test",
318 },
319 {
320 name: "vendor native test binary",
321 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700322 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700323 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900324 kind: socSpecificModule,
325 },
326 inData: true,
327 },
328 in: []string{"nativetest", "my_test"},
329 out: "target/product/test_device/data/nativetest/my_test",
330 },
331 {
332 name: "odm native test binary",
333 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700334 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900335 target: deviceTarget,
336 kind: deviceSpecificModule,
337 },
338 inData: true,
339 },
340 in: []string{"nativetest", "my_test"},
341 out: "target/product/test_device/data/nativetest/my_test",
342 },
343 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900344 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900345 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700346 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900347 target: deviceTarget,
348 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700349 },
350 inData: true,
351 },
352 in: []string{"nativetest", "my_test"},
353 out: "target/product/test_device/data/nativetest/my_test",
354 },
355
356 {
Justin Yund5f6c822019-06-25 16:47:17 +0900357 name: "system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100358 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700359 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100360 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900361 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100362 },
363 inData: true,
364 },
365 in: []string{"nativetest", "my_test"},
366 out: "target/product/test_device/data/nativetest/my_test",
367 },
368
369 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700370 name: "sanitized system binary",
371 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700372 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700373 target: deviceTarget,
374 },
375 inSanitizerDir: true,
376 },
377 in: []string{"bin", "my_test"},
378 out: "target/product/test_device/data/asan/system/bin/my_test",
379 },
380 {
381 name: "sanitized vendor binary",
382 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700383 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700384 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900385 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700386 },
387 inSanitizerDir: true,
388 },
389 in: []string{"bin", "my_test"},
390 out: "target/product/test_device/data/asan/vendor/bin/my_test",
391 },
Jiyong Park2db76922017-11-08 16:03:48 +0900392 {
393 name: "sanitized odm binary",
394 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700395 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900396 target: deviceTarget,
397 kind: deviceSpecificModule,
398 },
399 inSanitizerDir: true,
400 },
401 in: []string{"bin", "my_test"},
402 out: "target/product/test_device/data/asan/odm/bin/my_test",
403 },
404 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900405 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900406 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700407 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900408 target: deviceTarget,
409 kind: productSpecificModule,
410 },
411 inSanitizerDir: true,
412 },
413 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900414 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900415 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700416
417 {
Justin Yund5f6c822019-06-25 16:47:17 +0900418 name: "sanitized system_ext binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100419 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700420 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100421 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900422 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100423 },
424 inSanitizerDir: true,
425 },
426 in: []string{"bin", "my_test"},
Justin Yund5f6c822019-06-25 16:47:17 +0900427 out: "target/product/test_device/data/asan/system_ext/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100428 },
429
430 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700431 name: "sanitized system native test binary",
432 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700433 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700434 target: deviceTarget,
435 },
436 inData: true,
437 inSanitizerDir: true,
438 },
439 in: []string{"nativetest", "my_test"},
440 out: "target/product/test_device/data/asan/data/nativetest/my_test",
441 },
442 {
443 name: "sanitized vendor native test binary",
444 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700445 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700446 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900447 kind: socSpecificModule,
448 },
449 inData: true,
450 inSanitizerDir: true,
451 },
452 in: []string{"nativetest", "my_test"},
453 out: "target/product/test_device/data/asan/data/nativetest/my_test",
454 },
455 {
456 name: "sanitized odm native test binary",
457 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700458 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900459 target: deviceTarget,
460 kind: deviceSpecificModule,
461 },
462 inData: true,
463 inSanitizerDir: true,
464 },
465 in: []string{"nativetest", "my_test"},
466 out: "target/product/test_device/data/asan/data/nativetest/my_test",
467 },
468 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900469 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900470 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700471 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900472 target: deviceTarget,
473 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700474 },
475 inData: true,
476 inSanitizerDir: true,
477 },
478 in: []string{"nativetest", "my_test"},
479 out: "target/product/test_device/data/asan/data/nativetest/my_test",
480 },
Dario Frenifd05a742018-05-29 13:28:54 +0100481 {
Justin Yund5f6c822019-06-25 16:47:17 +0900482 name: "sanitized system_ext native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100483 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700484 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100485 target: deviceTarget,
Justin Yund5f6c822019-06-25 16:47:17 +0900486 kind: systemExtSpecificModule,
Dario Frenifd05a742018-05-29 13:28:54 +0100487 },
488 inData: true,
489 inSanitizerDir: true,
490 },
491 in: []string{"nativetest", "my_test"},
492 out: "target/product/test_device/data/asan/data/nativetest/my_test",
493 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700494 }
495
496 for _, tc := range testCases {
497 t.Run(tc.name, func(t *testing.T) {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700498 tc.ctx.baseModuleContext.config = testConfig
Dan Willemsen00269f22017-07-06 16:59:48 -0700499 output := PathForModuleInstall(tc.ctx, tc.in...)
500 if output.basePath.path != tc.out {
501 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
502 output.basePath.path,
503 tc.out)
504 }
505 })
506 }
507}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700508
509func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800510 config := TestConfig("out", nil)
511
512 ctx := PathContextForTesting(config, map[string][]byte{
513 "a.txt": nil,
514 "a/txt": nil,
515 "a/b/c": nil,
516 "a/b/d": nil,
517 "b": nil,
518 "b/b.txt": nil,
519 "a/a.txt": nil,
520 })
521
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700522 makePaths := func() Paths {
523 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800524 PathForSource(ctx, "a.txt"),
525 PathForSource(ctx, "a/txt"),
526 PathForSource(ctx, "a/b/c"),
527 PathForSource(ctx, "a/b/d"),
528 PathForSource(ctx, "b"),
529 PathForSource(ctx, "b/b.txt"),
530 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700531 }
532 }
533
534 expected := []string{
535 "a.txt",
536 "a/a.txt",
537 "a/b/c",
538 "a/b/d",
539 "a/txt",
540 "b",
541 "b/b.txt",
542 }
543
544 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700545 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700546
547 sortedPaths := PathsToDirectorySortedPaths(paths)
548 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
549
550 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
551 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
552 }
553
554 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
555 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
556 }
557
558 expectedA := []string{
559 "a/a.txt",
560 "a/b/c",
561 "a/b/d",
562 "a/txt",
563 }
564
565 inA := sortedPaths.PathsInDirectory("a")
566 if !reflect.DeepEqual(inA.Strings(), expectedA) {
567 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
568 }
569
570 expectedA_B := []string{
571 "a/b/c",
572 "a/b/d",
573 }
574
575 inA_B := sortedPaths.PathsInDirectory("a/b")
576 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
577 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
578 }
579
580 expectedB := []string{
581 "b/b.txt",
582 }
583
584 inB := sortedPaths.PathsInDirectory("b")
585 if !reflect.DeepEqual(inB.Strings(), expectedB) {
586 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
587 }
588}
Colin Cross43f08db2018-11-12 10:13:39 -0800589
590func TestMaybeRel(t *testing.T) {
591 testCases := []struct {
592 name string
593 base string
594 target string
595 out string
596 isRel bool
597 }{
598 {
599 name: "normal",
600 base: "a/b/c",
601 target: "a/b/c/d",
602 out: "d",
603 isRel: true,
604 },
605 {
606 name: "parent",
607 base: "a/b/c/d",
608 target: "a/b/c",
609 isRel: false,
610 },
611 {
612 name: "not relative",
613 base: "a/b",
614 target: "c/d",
615 isRel: false,
616 },
617 {
618 name: "abs1",
619 base: "/a",
620 target: "a",
621 isRel: false,
622 },
623 {
624 name: "abs2",
625 base: "a",
626 target: "/a",
627 isRel: false,
628 },
629 }
630
631 for _, testCase := range testCases {
632 t.Run(testCase.name, func(t *testing.T) {
633 ctx := &configErrorWrapper{}
634 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
635 if len(ctx.errors) > 0 {
636 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
637 testCase.base, testCase.target, ctx.errors)
638 }
639 if isRel != testCase.isRel || out != testCase.out {
640 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
641 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
642 }
643 })
644 }
645}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800646
647func TestPathForSource(t *testing.T) {
648 testCases := []struct {
649 name string
650 buildDir string
651 src string
652 err string
653 }{
654 {
655 name: "normal",
656 buildDir: "out",
657 src: "a/b/c",
658 },
659 {
660 name: "abs",
661 buildDir: "out",
662 src: "/a/b/c",
663 err: "is outside directory",
664 },
665 {
666 name: "in out dir",
667 buildDir: "out",
668 src: "out/a/b/c",
669 err: "is in output",
670 },
671 }
672
673 funcs := []struct {
674 name string
675 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
676 }{
677 {"pathForSource", pathForSource},
678 {"safePathForSource", safePathForSource},
679 }
680
681 for _, f := range funcs {
682 t.Run(f.name, func(t *testing.T) {
683 for _, test := range testCases {
684 t.Run(test.name, func(t *testing.T) {
685 testConfig := TestConfig(test.buildDir, nil)
686 ctx := &configErrorWrapper{config: testConfig}
687 _, err := f.f(ctx, test.src)
688 if len(ctx.errors) > 0 {
689 t.Fatalf("unexpected errors %v", ctx.errors)
690 }
691 if err != nil {
692 if test.err == "" {
693 t.Fatalf("unexpected error %q", err.Error())
694 } else if !strings.Contains(err.Error(), test.err) {
695 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
696 }
697 } else {
698 if test.err != "" {
699 t.Fatalf("missing error %q", test.err)
700 }
701 }
702 })
703 }
704 })
705 }
706}
Colin Cross8854a5a2019-02-11 14:14:16 -0800707
Colin Cross8a497952019-03-05 22:25:09 -0800708type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800709 ModuleBase
710 props struct {
711 Srcs []string `android:"path"`
712 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800713
714 Src *string `android:"path"`
Colin Crossba71a3f2019-03-18 12:12:48 -0700715
716 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800717 }
718
Colin Cross8a497952019-03-05 22:25:09 -0800719 src string
720 rel string
721
722 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800723 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800724
725 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800726}
727
Colin Cross8a497952019-03-05 22:25:09 -0800728func pathForModuleSrcTestModuleFactory() Module {
729 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800730 module.AddProperties(&module.props)
731 InitAndroidModule(module)
732 return module
733}
734
Colin Cross8a497952019-03-05 22:25:09 -0800735func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossba71a3f2019-03-18 12:12:48 -0700736 var srcs Paths
737 if p.props.Module_handles_missing_deps {
738 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
739 } else {
740 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
741 }
Colin Cross8a497952019-03-05 22:25:09 -0800742 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800743
Colin Cross8a497952019-03-05 22:25:09 -0800744 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800745 p.rels = append(p.rels, src.Rel())
746 }
Colin Cross8a497952019-03-05 22:25:09 -0800747
748 if p.props.Src != nil {
749 src := PathForModuleSrc(ctx, *p.props.Src)
750 if src != nil {
751 p.src = src.String()
752 p.rel = src.Rel()
753 }
754 }
755
Colin Crossba71a3f2019-03-18 12:12:48 -0700756 if !p.props.Module_handles_missing_deps {
757 p.missingDeps = ctx.GetMissingDependencies()
758 }
Colin Cross6c4f21f2019-06-06 15:41:36 -0700759
760 ctx.Build(pctx, BuildParams{
761 Rule: Touch,
762 Output: PathForModuleOut(ctx, "output"),
763 })
Colin Cross8a497952019-03-05 22:25:09 -0800764}
765
Colin Cross41955e82019-05-29 14:40:35 -0700766type pathForModuleSrcOutputFileProviderModule struct {
767 ModuleBase
768 props struct {
769 Outs []string
770 Tagged []string
771 }
772
773 outs Paths
774 tagged Paths
775}
776
777func pathForModuleSrcOutputFileProviderModuleFactory() Module {
778 module := &pathForModuleSrcOutputFileProviderModule{}
779 module.AddProperties(&module.props)
780 InitAndroidModule(module)
781 return module
782}
783
784func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
785 for _, out := range p.props.Outs {
786 p.outs = append(p.outs, PathForModuleOut(ctx, out))
787 }
788
789 for _, tagged := range p.props.Tagged {
790 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
791 }
792}
793
794func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
795 switch tag {
796 case "":
797 return p.outs, nil
798 case ".tagged":
799 return p.tagged, nil
800 default:
801 return nil, fmt.Errorf("unsupported tag %q", tag)
802 }
803}
804
Colin Cross8a497952019-03-05 22:25:09 -0800805type pathForModuleSrcTestCase struct {
806 name string
807 bp string
808 srcs []string
809 rels []string
810 src string
811 rel string
812}
813
814func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
815 for _, test := range tests {
816 t.Run(test.name, func(t *testing.T) {
817 config := TestConfig(buildDir, nil)
818 ctx := NewTestContext()
819
820 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
Colin Cross41955e82019-05-29 14:40:35 -0700821 ctx.RegisterModuleType("output_file_provider", ModuleFactoryAdaptor(pathForModuleSrcOutputFileProviderModuleFactory))
Colin Cross8a497952019-03-05 22:25:09 -0800822 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
823
824 fgBp := `
825 filegroup {
826 name: "a",
827 srcs: ["src/a"],
828 }
829 `
830
Colin Cross41955e82019-05-29 14:40:35 -0700831 ofpBp := `
832 output_file_provider {
833 name: "b",
834 outs: ["gen/b"],
835 tagged: ["gen/c"],
836 }
837 `
838
Colin Cross8a497952019-03-05 22:25:09 -0800839 mockFS := map[string][]byte{
840 "fg/Android.bp": []byte(fgBp),
841 "foo/Android.bp": []byte(test.bp),
Colin Cross41955e82019-05-29 14:40:35 -0700842 "ofp/Android.bp": []byte(ofpBp),
Colin Cross8a497952019-03-05 22:25:09 -0800843 "fg/src/a": nil,
844 "foo/src/b": nil,
845 "foo/src/c": nil,
846 "foo/src/d": nil,
847 "foo/src/e/e": nil,
848 "foo/src_special/$": nil,
849 }
850
851 ctx.MockFileSystem(mockFS)
852
853 ctx.Register()
Colin Cross41955e82019-05-29 14:40:35 -0700854 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
Colin Cross8a497952019-03-05 22:25:09 -0800855 FailIfErrored(t, errs)
856 _, errs = ctx.PrepareBuildActions(config)
857 FailIfErrored(t, errs)
858
859 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
860
861 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
862 t.Errorf("want srcs %q, got %q", w, g)
863 }
864
865 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
866 t.Errorf("want rels %q, got %q", w, g)
867 }
868
869 if g, w := m.src, test.src; g != w {
870 t.Errorf("want src %q, got %q", w, g)
871 }
872
873 if g, w := m.rel, test.rel; g != w {
874 t.Errorf("want rel %q, got %q", w, g)
875 }
876 })
877 }
Colin Cross937664a2019-03-06 10:17:32 -0800878}
879
Colin Cross8a497952019-03-05 22:25:09 -0800880func TestPathsForModuleSrc(t *testing.T) {
881 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800882 {
883 name: "path",
884 bp: `
885 test {
886 name: "foo",
887 srcs: ["src/b"],
888 }`,
889 srcs: []string{"foo/src/b"},
890 rels: []string{"src/b"},
891 },
892 {
893 name: "glob",
894 bp: `
895 test {
896 name: "foo",
897 srcs: [
898 "src/*",
899 "src/e/*",
900 ],
901 }`,
902 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
903 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
904 },
905 {
906 name: "recursive glob",
907 bp: `
908 test {
909 name: "foo",
910 srcs: ["src/**/*"],
911 }`,
912 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
913 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
914 },
915 {
916 name: "filegroup",
917 bp: `
918 test {
919 name: "foo",
920 srcs: [":a"],
921 }`,
922 srcs: []string{"fg/src/a"},
923 rels: []string{"src/a"},
924 },
925 {
Colin Cross41955e82019-05-29 14:40:35 -0700926 name: "output file provider",
927 bp: `
928 test {
929 name: "foo",
930 srcs: [":b"],
931 }`,
932 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
933 rels: []string{"gen/b"},
934 },
935 {
936 name: "output file provider tagged",
937 bp: `
938 test {
939 name: "foo",
940 srcs: [":b{.tagged}"],
941 }`,
942 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
943 rels: []string{"gen/c"},
944 },
945 {
Colin Cross937664a2019-03-06 10:17:32 -0800946 name: "special characters glob",
947 bp: `
948 test {
949 name: "foo",
950 srcs: ["src_special/*"],
951 }`,
952 srcs: []string{"foo/src_special/$"},
953 rels: []string{"src_special/$"},
954 },
955 }
956
Colin Cross41955e82019-05-29 14:40:35 -0700957 testPathForModuleSrc(t, buildDir, tests)
958}
959
960func TestPathForModuleSrc(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -0800961 tests := []pathForModuleSrcTestCase{
962 {
963 name: "path",
964 bp: `
965 test {
966 name: "foo",
967 src: "src/b",
968 }`,
969 src: "foo/src/b",
970 rel: "src/b",
971 },
972 {
973 name: "glob",
974 bp: `
975 test {
976 name: "foo",
977 src: "src/e/*",
978 }`,
979 src: "foo/src/e/e",
980 rel: "src/e/e",
981 },
982 {
983 name: "filegroup",
984 bp: `
985 test {
986 name: "foo",
987 src: ":a",
988 }`,
989 src: "fg/src/a",
990 rel: "src/a",
991 },
992 {
Colin Cross41955e82019-05-29 14:40:35 -0700993 name: "output file provider",
994 bp: `
995 test {
996 name: "foo",
997 src: ":b",
998 }`,
999 src: buildDir + "/.intermediates/ofp/b/gen/b",
1000 rel: "gen/b",
1001 },
1002 {
1003 name: "output file provider tagged",
1004 bp: `
1005 test {
1006 name: "foo",
1007 src: ":b{.tagged}",
1008 }`,
1009 src: buildDir + "/.intermediates/ofp/b/gen/c",
1010 rel: "gen/c",
1011 },
1012 {
Colin Cross8a497952019-03-05 22:25:09 -08001013 name: "special characters glob",
1014 bp: `
1015 test {
1016 name: "foo",
1017 src: "src_special/*",
1018 }`,
1019 src: "foo/src_special/$",
1020 rel: "src_special/$",
1021 },
1022 }
1023
Colin Cross8a497952019-03-05 22:25:09 -08001024 testPathForModuleSrc(t, buildDir, tests)
1025}
Colin Cross937664a2019-03-06 10:17:32 -08001026
Colin Cross8a497952019-03-05 22:25:09 -08001027func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
Colin Cross8a497952019-03-05 22:25:09 -08001028 config := TestConfig(buildDir, nil)
1029 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
1030
1031 ctx := NewTestContext()
1032 ctx.SetAllowMissingDependencies(true)
1033
1034 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
1035
1036 bp := `
1037 test {
1038 name: "foo",
1039 srcs: [":a"],
1040 exclude_srcs: [":b"],
1041 src: ":c",
1042 }
Colin Crossba71a3f2019-03-18 12:12:48 -07001043
1044 test {
1045 name: "bar",
1046 srcs: [":d"],
1047 exclude_srcs: [":e"],
1048 module_handles_missing_deps: true,
1049 }
Colin Cross8a497952019-03-05 22:25:09 -08001050 `
1051
1052 mockFS := map[string][]byte{
1053 "Android.bp": []byte(bp),
1054 }
1055
1056 ctx.MockFileSystem(mockFS)
1057
1058 ctx.Register()
1059 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
1060 FailIfErrored(t, errs)
1061 _, errs = ctx.PrepareBuildActions(config)
1062 FailIfErrored(t, errs)
1063
1064 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
1065
1066 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001067 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001068 }
1069
1070 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001071 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001072 }
1073
1074 if g, w := foo.src, ""; g != w {
Colin Crossba71a3f2019-03-18 12:12:48 -07001075 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001076 }
1077
Colin Crossba71a3f2019-03-18 12:12:48 -07001078 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1079
1080 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1081 t.Errorf("want bar missing deps %q, got %q", w, g)
1082 }
1083
1084 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1085 t.Errorf("want bar srcs %q, got %q", w, g)
1086 }
Colin Cross937664a2019-03-06 10:17:32 -08001087}
1088
Colin Cross8854a5a2019-02-11 14:14:16 -08001089func ExampleOutputPath_ReplaceExtension() {
1090 ctx := &configErrorWrapper{
1091 config: TestConfig("out", nil),
1092 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001093 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -08001094 p2 := p.ReplaceExtension(ctx, "oat")
1095 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001096 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -08001097
1098 // Output:
1099 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -08001100 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -08001101}
Colin Cross40e33732019-02-15 11:08:35 -08001102
1103func ExampleOutputPath_FileInSameDir() {
1104 ctx := &configErrorWrapper{
1105 config: TestConfig("out", nil),
1106 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001107 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001108 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1109 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001110 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001111
1112 // Output:
1113 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001114 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001115}