blob: e0c2f6c962c108912d4caba3c0b7aab3caf780ef [file] [log] [blame]
Dan Willemsen34cc69e2015-09-23 15:26:20 -07001// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Dan Willemsen34cc69e2015-09-23 15:26:20 -070016
17import (
18 "errors"
19 "fmt"
Colin Cross937664a2019-03-06 10:17:32 -080020 "io/ioutil"
21 "os"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070022 "reflect"
23 "strings"
24 "testing"
Dan Willemsen00269f22017-07-06 16:59:48 -070025
26 "github.com/google/blueprint/pathtools"
Colin Cross8a497952019-03-05 22:25:09 -080027 "github.com/google/blueprint/proptools"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070028)
29
30type strsTestCase struct {
31 in []string
32 out string
33 err []error
34}
35
36var commonValidatePathTestCases = []strsTestCase{
37 {
38 in: []string{""},
39 out: "",
40 },
41 {
42 in: []string{"a/b"},
43 out: "a/b",
44 },
45 {
46 in: []string{"a/b", "c"},
47 out: "a/b/c",
48 },
49 {
50 in: []string{"a/.."},
51 out: ".",
52 },
53 {
54 in: []string{"."},
55 out: ".",
56 },
57 {
58 in: []string{".."},
59 out: "",
60 err: []error{errors.New("Path is outside directory: ..")},
61 },
62 {
63 in: []string{"../a"},
64 out: "",
65 err: []error{errors.New("Path is outside directory: ../a")},
66 },
67 {
68 in: []string{"b/../../a"},
69 out: "",
70 err: []error{errors.New("Path is outside directory: ../a")},
71 },
72 {
73 in: []string{"/a"},
74 out: "",
75 err: []error{errors.New("Path is outside directory: /a")},
76 },
Dan Willemsen80a7c2a2015-12-21 14:57:11 -080077 {
78 in: []string{"a", "../b"},
79 out: "",
80 err: []error{errors.New("Path is outside directory: ../b")},
81 },
82 {
83 in: []string{"a", "b/../../c"},
84 out: "",
85 err: []error{errors.New("Path is outside directory: ../c")},
86 },
87 {
88 in: []string{"a", "./.."},
89 out: "",
90 err: []error{errors.New("Path is outside directory: ..")},
91 },
Dan Willemsen34cc69e2015-09-23 15:26:20 -070092}
93
94var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
95 {
96 in: []string{"$host/../$a"},
97 out: "$a",
98 },
99}...)
100
101var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
102 {
103 in: []string{"$host/../$a"},
104 out: "",
105 err: []error{errors.New("Path contains invalid character($): $host/../$a")},
106 },
107 {
108 in: []string{"$host/.."},
109 out: "",
110 err: []error{errors.New("Path contains invalid character($): $host/..")},
111 },
112}...)
113
114func TestValidateSafePath(t *testing.T) {
115 for _, testCase := range validateSafePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800116 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
117 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800118 out, err := validateSafePath(testCase.in...)
119 if err != nil {
120 reportPathError(ctx, err)
121 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800122 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
123 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700124 }
125}
126
127func TestValidatePath(t *testing.T) {
128 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800129 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
130 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800131 out, err := validatePath(testCase.in...)
132 if err != nil {
133 reportPathError(ctx, err)
134 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800135 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
136 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700137 }
138}
139
140func TestOptionalPath(t *testing.T) {
141 var path OptionalPath
142 checkInvalidOptionalPath(t, path)
143
144 path = OptionalPathForPath(nil)
145 checkInvalidOptionalPath(t, path)
146}
147
148func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800149 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700150 if path.Valid() {
151 t.Errorf("Uninitialized OptionalPath should not be valid")
152 }
153 if path.String() != "" {
154 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
155 }
156 defer func() {
157 if r := recover(); r == nil {
158 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
159 }
160 }()
161 path.Path()
162}
163
164func check(t *testing.T, testType, testString string,
165 got interface{}, err []error,
166 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800167 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700168
169 printedTestCase := false
170 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800171 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700172 if !printedTestCase {
173 t.Errorf("test case %s: %s", testType, testString)
174 printedTestCase = true
175 }
176 t.Errorf("incorrect %s", s)
177 t.Errorf(" expected: %s", p(expected))
178 t.Errorf(" got: %s", p(got))
179 }
180
181 if !reflect.DeepEqual(expectedErr, err) {
182 e("errors:", expectedErr, err)
183 }
184
185 if !reflect.DeepEqual(expected, got) {
186 e("output:", expected, got)
187 }
188}
189
190func p(in interface{}) string {
191 if v, ok := in.([]interface{}); ok {
192 s := make([]string, len(v))
193 for i := range v {
194 s[i] = fmt.Sprintf("%#v", v[i])
195 }
196 return "[" + strings.Join(s, ", ") + "]"
197 } else {
198 return fmt.Sprintf("%#v", in)
199 }
200}
Dan Willemsen00269f22017-07-06 16:59:48 -0700201
202type moduleInstallPathContextImpl struct {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700203 baseModuleContext
Dan Willemsen00269f22017-07-06 16:59:48 -0700204
205 inData bool
206 inSanitizerDir bool
Jiyong Parkf9332f12018-02-01 00:54:12 +0900207 inRecovery 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
224func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
225 return m.inSanitizerDir
226}
227
Jiyong Parkf9332f12018-02-01 00:54:12 +0900228func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
229 return m.inRecovery
230}
231
Dan Willemsen00269f22017-07-06 16:59:48 -0700232func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700233 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700234
235 hostTarget := Target{Os: Linux}
236 deviceTarget := Target{Os: Android}
237
238 testCases := []struct {
239 name string
240 ctx *moduleInstallPathContextImpl
241 in []string
242 out string
243 }{
244 {
245 name: "host binary",
246 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700247 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700248 target: hostTarget,
249 },
250 },
251 in: []string{"bin", "my_test"},
252 out: "host/linux-x86/bin/my_test",
253 },
254
255 {
256 name: "system binary",
257 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700258 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700259 target: deviceTarget,
260 },
261 },
262 in: []string{"bin", "my_test"},
263 out: "target/product/test_device/system/bin/my_test",
264 },
265 {
266 name: "vendor binary",
267 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700268 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700269 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900270 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700271 },
272 },
273 in: []string{"bin", "my_test"},
274 out: "target/product/test_device/vendor/bin/my_test",
275 },
Jiyong Park2db76922017-11-08 16:03:48 +0900276 {
277 name: "odm binary",
278 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700279 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900280 target: deviceTarget,
281 kind: deviceSpecificModule,
282 },
283 },
284 in: []string{"bin", "my_test"},
285 out: "target/product/test_device/odm/bin/my_test",
286 },
287 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900288 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900289 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700290 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900291 target: deviceTarget,
292 kind: productSpecificModule,
293 },
294 },
295 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900296 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900297 },
Dario Frenifd05a742018-05-29 13:28:54 +0100298 {
Dario Freni95cf7672018-08-17 00:57:57 +0100299 name: "product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100300 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700301 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100302 target: deviceTarget,
303 kind: productServicesSpecificModule,
304 },
305 },
306 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100307 out: "target/product/test_device/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100308 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700309
310 {
311 name: "system native test binary",
312 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700313 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700314 target: deviceTarget,
315 },
316 inData: true,
317 },
318 in: []string{"nativetest", "my_test"},
319 out: "target/product/test_device/data/nativetest/my_test",
320 },
321 {
322 name: "vendor native test binary",
323 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700324 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700325 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900326 kind: socSpecificModule,
327 },
328 inData: true,
329 },
330 in: []string{"nativetest", "my_test"},
331 out: "target/product/test_device/data/nativetest/my_test",
332 },
333 {
334 name: "odm native test binary",
335 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700336 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900337 target: deviceTarget,
338 kind: deviceSpecificModule,
339 },
340 inData: true,
341 },
342 in: []string{"nativetest", "my_test"},
343 out: "target/product/test_device/data/nativetest/my_test",
344 },
345 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900346 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900347 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700348 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900349 target: deviceTarget,
350 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700351 },
352 inData: true,
353 },
354 in: []string{"nativetest", "my_test"},
355 out: "target/product/test_device/data/nativetest/my_test",
356 },
357
358 {
Dario Freni95cf7672018-08-17 00:57:57 +0100359 name: "product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100360 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700361 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100362 target: deviceTarget,
363 kind: productServicesSpecificModule,
364 },
365 inData: true,
366 },
367 in: []string{"nativetest", "my_test"},
368 out: "target/product/test_device/data/nativetest/my_test",
369 },
370
371 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700372 name: "sanitized system binary",
373 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700374 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700375 target: deviceTarget,
376 },
377 inSanitizerDir: true,
378 },
379 in: []string{"bin", "my_test"},
380 out: "target/product/test_device/data/asan/system/bin/my_test",
381 },
382 {
383 name: "sanitized vendor binary",
384 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700385 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700386 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900387 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700388 },
389 inSanitizerDir: true,
390 },
391 in: []string{"bin", "my_test"},
392 out: "target/product/test_device/data/asan/vendor/bin/my_test",
393 },
Jiyong Park2db76922017-11-08 16:03:48 +0900394 {
395 name: "sanitized odm binary",
396 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700397 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900398 target: deviceTarget,
399 kind: deviceSpecificModule,
400 },
401 inSanitizerDir: true,
402 },
403 in: []string{"bin", "my_test"},
404 out: "target/product/test_device/data/asan/odm/bin/my_test",
405 },
406 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900407 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900408 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700409 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900410 target: deviceTarget,
411 kind: productSpecificModule,
412 },
413 inSanitizerDir: true,
414 },
415 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900416 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900417 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700418
419 {
Dario Freni95cf7672018-08-17 00:57:57 +0100420 name: "sanitized product_services binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100421 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700422 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100423 target: deviceTarget,
424 kind: productServicesSpecificModule,
425 },
426 inSanitizerDir: true,
427 },
428 in: []string{"bin", "my_test"},
Dario Freni95cf7672018-08-17 00:57:57 +0100429 out: "target/product/test_device/data/asan/product_services/bin/my_test",
Dario Frenifd05a742018-05-29 13:28:54 +0100430 },
431
432 {
Dan Willemsen00269f22017-07-06 16:59:48 -0700433 name: "sanitized system native test binary",
434 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700435 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700436 target: deviceTarget,
437 },
438 inData: true,
439 inSanitizerDir: true,
440 },
441 in: []string{"nativetest", "my_test"},
442 out: "target/product/test_device/data/asan/data/nativetest/my_test",
443 },
444 {
445 name: "sanitized vendor native test binary",
446 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700447 baseModuleContext: baseModuleContext{
Dan Willemsen00269f22017-07-06 16:59:48 -0700448 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900449 kind: socSpecificModule,
450 },
451 inData: true,
452 inSanitizerDir: true,
453 },
454 in: []string{"nativetest", "my_test"},
455 out: "target/product/test_device/data/asan/data/nativetest/my_test",
456 },
457 {
458 name: "sanitized odm native test binary",
459 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700460 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900461 target: deviceTarget,
462 kind: deviceSpecificModule,
463 },
464 inData: true,
465 inSanitizerDir: true,
466 },
467 in: []string{"nativetest", "my_test"},
468 out: "target/product/test_device/data/asan/data/nativetest/my_test",
469 },
470 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900471 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900472 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700473 baseModuleContext: baseModuleContext{
Jiyong Park2db76922017-11-08 16:03:48 +0900474 target: deviceTarget,
475 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700476 },
477 inData: true,
478 inSanitizerDir: true,
479 },
480 in: []string{"nativetest", "my_test"},
481 out: "target/product/test_device/data/asan/data/nativetest/my_test",
482 },
Dario Frenifd05a742018-05-29 13:28:54 +0100483 {
Dario Freni95cf7672018-08-17 00:57:57 +0100484 name: "sanitized product_services native test binary",
Dario Frenifd05a742018-05-29 13:28:54 +0100485 ctx: &moduleInstallPathContextImpl{
Colin Cross0ea8ba82019-06-06 14:33:29 -0700486 baseModuleContext: baseModuleContext{
Dario Frenifd05a742018-05-29 13:28:54 +0100487 target: deviceTarget,
488 kind: productServicesSpecificModule,
489 },
490 inData: true,
491 inSanitizerDir: true,
492 },
493 in: []string{"nativetest", "my_test"},
494 out: "target/product/test_device/data/asan/data/nativetest/my_test",
495 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700496 }
497
498 for _, tc := range testCases {
499 t.Run(tc.name, func(t *testing.T) {
Colin Cross0ea8ba82019-06-06 14:33:29 -0700500 tc.ctx.baseModuleContext.config = testConfig
Dan Willemsen00269f22017-07-06 16:59:48 -0700501 output := PathForModuleInstall(tc.ctx, tc.in...)
502 if output.basePath.path != tc.out {
503 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
504 output.basePath.path,
505 tc.out)
506 }
507 })
508 }
509}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700510
511func TestDirectorySortedPaths(t *testing.T) {
Colin Cross07e51612019-03-05 12:46:40 -0800512 config := TestConfig("out", nil)
513
514 ctx := PathContextForTesting(config, map[string][]byte{
515 "a.txt": nil,
516 "a/txt": nil,
517 "a/b/c": nil,
518 "a/b/d": nil,
519 "b": nil,
520 "b/b.txt": nil,
521 "a/a.txt": nil,
522 })
523
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700524 makePaths := func() Paths {
525 return Paths{
Colin Cross07e51612019-03-05 12:46:40 -0800526 PathForSource(ctx, "a.txt"),
527 PathForSource(ctx, "a/txt"),
528 PathForSource(ctx, "a/b/c"),
529 PathForSource(ctx, "a/b/d"),
530 PathForSource(ctx, "b"),
531 PathForSource(ctx, "b/b.txt"),
532 PathForSource(ctx, "a/a.txt"),
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700533 }
534 }
535
536 expected := []string{
537 "a.txt",
538 "a/a.txt",
539 "a/b/c",
540 "a/b/d",
541 "a/txt",
542 "b",
543 "b/b.txt",
544 }
545
546 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700547 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700548
549 sortedPaths := PathsToDirectorySortedPaths(paths)
550 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
551
552 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
553 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
554 }
555
556 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
557 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
558 }
559
560 expectedA := []string{
561 "a/a.txt",
562 "a/b/c",
563 "a/b/d",
564 "a/txt",
565 }
566
567 inA := sortedPaths.PathsInDirectory("a")
568 if !reflect.DeepEqual(inA.Strings(), expectedA) {
569 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
570 }
571
572 expectedA_B := []string{
573 "a/b/c",
574 "a/b/d",
575 }
576
577 inA_B := sortedPaths.PathsInDirectory("a/b")
578 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
579 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
580 }
581
582 expectedB := []string{
583 "b/b.txt",
584 }
585
586 inB := sortedPaths.PathsInDirectory("b")
587 if !reflect.DeepEqual(inB.Strings(), expectedB) {
588 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
589 }
590}
Colin Cross43f08db2018-11-12 10:13:39 -0800591
592func TestMaybeRel(t *testing.T) {
593 testCases := []struct {
594 name string
595 base string
596 target string
597 out string
598 isRel bool
599 }{
600 {
601 name: "normal",
602 base: "a/b/c",
603 target: "a/b/c/d",
604 out: "d",
605 isRel: true,
606 },
607 {
608 name: "parent",
609 base: "a/b/c/d",
610 target: "a/b/c",
611 isRel: false,
612 },
613 {
614 name: "not relative",
615 base: "a/b",
616 target: "c/d",
617 isRel: false,
618 },
619 {
620 name: "abs1",
621 base: "/a",
622 target: "a",
623 isRel: false,
624 },
625 {
626 name: "abs2",
627 base: "a",
628 target: "/a",
629 isRel: false,
630 },
631 }
632
633 for _, testCase := range testCases {
634 t.Run(testCase.name, func(t *testing.T) {
635 ctx := &configErrorWrapper{}
636 out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
637 if len(ctx.errors) > 0 {
638 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
639 testCase.base, testCase.target, ctx.errors)
640 }
641 if isRel != testCase.isRel || out != testCase.out {
642 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
643 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
644 }
645 })
646 }
647}
Colin Cross7b3dcc32019-01-24 13:14:39 -0800648
649func TestPathForSource(t *testing.T) {
650 testCases := []struct {
651 name string
652 buildDir string
653 src string
654 err string
655 }{
656 {
657 name: "normal",
658 buildDir: "out",
659 src: "a/b/c",
660 },
661 {
662 name: "abs",
663 buildDir: "out",
664 src: "/a/b/c",
665 err: "is outside directory",
666 },
667 {
668 name: "in out dir",
669 buildDir: "out",
670 src: "out/a/b/c",
671 err: "is in output",
672 },
673 }
674
675 funcs := []struct {
676 name string
677 f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
678 }{
679 {"pathForSource", pathForSource},
680 {"safePathForSource", safePathForSource},
681 }
682
683 for _, f := range funcs {
684 t.Run(f.name, func(t *testing.T) {
685 for _, test := range testCases {
686 t.Run(test.name, func(t *testing.T) {
687 testConfig := TestConfig(test.buildDir, nil)
688 ctx := &configErrorWrapper{config: testConfig}
689 _, err := f.f(ctx, test.src)
690 if len(ctx.errors) > 0 {
691 t.Fatalf("unexpected errors %v", ctx.errors)
692 }
693 if err != nil {
694 if test.err == "" {
695 t.Fatalf("unexpected error %q", err.Error())
696 } else if !strings.Contains(err.Error(), test.err) {
697 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
698 }
699 } else {
700 if test.err != "" {
701 t.Fatalf("missing error %q", test.err)
702 }
703 }
704 })
705 }
706 })
707 }
708}
Colin Cross8854a5a2019-02-11 14:14:16 -0800709
Colin Cross8a497952019-03-05 22:25:09 -0800710type pathForModuleSrcTestModule struct {
Colin Cross937664a2019-03-06 10:17:32 -0800711 ModuleBase
712 props struct {
713 Srcs []string `android:"path"`
714 Exclude_srcs []string `android:"path"`
Colin Cross8a497952019-03-05 22:25:09 -0800715
716 Src *string `android:"path"`
Colin Crossba71a3f2019-03-18 12:12:48 -0700717
718 Module_handles_missing_deps bool
Colin Cross937664a2019-03-06 10:17:32 -0800719 }
720
Colin Cross8a497952019-03-05 22:25:09 -0800721 src string
722 rel string
723
724 srcs []string
Colin Cross937664a2019-03-06 10:17:32 -0800725 rels []string
Colin Cross8a497952019-03-05 22:25:09 -0800726
727 missingDeps []string
Colin Cross937664a2019-03-06 10:17:32 -0800728}
729
Colin Cross8a497952019-03-05 22:25:09 -0800730func pathForModuleSrcTestModuleFactory() Module {
731 module := &pathForModuleSrcTestModule{}
Colin Cross937664a2019-03-06 10:17:32 -0800732 module.AddProperties(&module.props)
733 InitAndroidModule(module)
734 return module
735}
736
Colin Cross8a497952019-03-05 22:25:09 -0800737func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Crossba71a3f2019-03-18 12:12:48 -0700738 var srcs Paths
739 if p.props.Module_handles_missing_deps {
740 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
741 } else {
742 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
743 }
Colin Cross8a497952019-03-05 22:25:09 -0800744 p.srcs = srcs.Strings()
Colin Cross937664a2019-03-06 10:17:32 -0800745
Colin Cross8a497952019-03-05 22:25:09 -0800746 for _, src := range srcs {
Colin Cross937664a2019-03-06 10:17:32 -0800747 p.rels = append(p.rels, src.Rel())
748 }
Colin Cross8a497952019-03-05 22:25:09 -0800749
750 if p.props.Src != nil {
751 src := PathForModuleSrc(ctx, *p.props.Src)
752 if src != nil {
753 p.src = src.String()
754 p.rel = src.Rel()
755 }
756 }
757
Colin Crossba71a3f2019-03-18 12:12:48 -0700758 if !p.props.Module_handles_missing_deps {
759 p.missingDeps = ctx.GetMissingDependencies()
760 }
Colin Cross6c4f21f2019-06-06 15:41:36 -0700761
762 ctx.Build(pctx, BuildParams{
763 Rule: Touch,
764 Output: PathForModuleOut(ctx, "output"),
765 })
Colin Cross8a497952019-03-05 22:25:09 -0800766}
767
Colin Cross41955e82019-05-29 14:40:35 -0700768type pathForModuleSrcOutputFileProviderModule struct {
769 ModuleBase
770 props struct {
771 Outs []string
772 Tagged []string
773 }
774
775 outs Paths
776 tagged Paths
777}
778
779func pathForModuleSrcOutputFileProviderModuleFactory() Module {
780 module := &pathForModuleSrcOutputFileProviderModule{}
781 module.AddProperties(&module.props)
782 InitAndroidModule(module)
783 return module
784}
785
786func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
787 for _, out := range p.props.Outs {
788 p.outs = append(p.outs, PathForModuleOut(ctx, out))
789 }
790
791 for _, tagged := range p.props.Tagged {
792 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged))
793 }
794}
795
796func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) {
797 switch tag {
798 case "":
799 return p.outs, nil
800 case ".tagged":
801 return p.tagged, nil
802 default:
803 return nil, fmt.Errorf("unsupported tag %q", tag)
804 }
805}
806
Colin Cross8a497952019-03-05 22:25:09 -0800807type pathForModuleSrcTestCase struct {
808 name string
809 bp string
810 srcs []string
811 rels []string
812 src string
813 rel string
814}
815
816func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
817 for _, test := range tests {
818 t.Run(test.name, func(t *testing.T) {
819 config := TestConfig(buildDir, nil)
820 ctx := NewTestContext()
821
822 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
Colin Cross41955e82019-05-29 14:40:35 -0700823 ctx.RegisterModuleType("output_file_provider", ModuleFactoryAdaptor(pathForModuleSrcOutputFileProviderModuleFactory))
Colin Cross8a497952019-03-05 22:25:09 -0800824 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
825
826 fgBp := `
827 filegroup {
828 name: "a",
829 srcs: ["src/a"],
830 }
831 `
832
Colin Cross41955e82019-05-29 14:40:35 -0700833 ofpBp := `
834 output_file_provider {
835 name: "b",
836 outs: ["gen/b"],
837 tagged: ["gen/c"],
838 }
839 `
840
Colin Cross8a497952019-03-05 22:25:09 -0800841 mockFS := map[string][]byte{
842 "fg/Android.bp": []byte(fgBp),
843 "foo/Android.bp": []byte(test.bp),
Colin Cross41955e82019-05-29 14:40:35 -0700844 "ofp/Android.bp": []byte(ofpBp),
Colin Cross8a497952019-03-05 22:25:09 -0800845 "fg/src/a": nil,
846 "foo/src/b": nil,
847 "foo/src/c": nil,
848 "foo/src/d": nil,
849 "foo/src/e/e": nil,
850 "foo/src_special/$": nil,
851 }
852
853 ctx.MockFileSystem(mockFS)
854
855 ctx.Register()
Colin Cross41955e82019-05-29 14:40:35 -0700856 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp", "ofp/Android.bp"})
Colin Cross8a497952019-03-05 22:25:09 -0800857 FailIfErrored(t, errs)
858 _, errs = ctx.PrepareBuildActions(config)
859 FailIfErrored(t, errs)
860
861 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
862
863 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
864 t.Errorf("want srcs %q, got %q", w, g)
865 }
866
867 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
868 t.Errorf("want rels %q, got %q", w, g)
869 }
870
871 if g, w := m.src, test.src; g != w {
872 t.Errorf("want src %q, got %q", w, g)
873 }
874
875 if g, w := m.rel, test.rel; g != w {
876 t.Errorf("want rel %q, got %q", w, g)
877 }
878 })
879 }
Colin Cross937664a2019-03-06 10:17:32 -0800880}
881
Colin Cross8a497952019-03-05 22:25:09 -0800882func TestPathsForModuleSrc(t *testing.T) {
Colin Cross41955e82019-05-29 14:40:35 -0700883 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test")
884 if err != nil {
885 t.Fatal(err)
886 }
887 defer os.RemoveAll(buildDir)
888
Colin Cross8a497952019-03-05 22:25:09 -0800889 tests := []pathForModuleSrcTestCase{
Colin Cross937664a2019-03-06 10:17:32 -0800890 {
891 name: "path",
892 bp: `
893 test {
894 name: "foo",
895 srcs: ["src/b"],
896 }`,
897 srcs: []string{"foo/src/b"},
898 rels: []string{"src/b"},
899 },
900 {
901 name: "glob",
902 bp: `
903 test {
904 name: "foo",
905 srcs: [
906 "src/*",
907 "src/e/*",
908 ],
909 }`,
910 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
911 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
912 },
913 {
914 name: "recursive glob",
915 bp: `
916 test {
917 name: "foo",
918 srcs: ["src/**/*"],
919 }`,
920 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
921 rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
922 },
923 {
924 name: "filegroup",
925 bp: `
926 test {
927 name: "foo",
928 srcs: [":a"],
929 }`,
930 srcs: []string{"fg/src/a"},
931 rels: []string{"src/a"},
932 },
933 {
Colin Cross41955e82019-05-29 14:40:35 -0700934 name: "output file provider",
935 bp: `
936 test {
937 name: "foo",
938 srcs: [":b"],
939 }`,
940 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
941 rels: []string{"gen/b"},
942 },
943 {
944 name: "output file provider tagged",
945 bp: `
946 test {
947 name: "foo",
948 srcs: [":b{.tagged}"],
949 }`,
950 srcs: []string{buildDir + "/.intermediates/ofp/b/gen/c"},
951 rels: []string{"gen/c"},
952 },
953 {
Colin Cross937664a2019-03-06 10:17:32 -0800954 name: "special characters glob",
955 bp: `
956 test {
957 name: "foo",
958 srcs: ["src_special/*"],
959 }`,
960 srcs: []string{"foo/src_special/$"},
961 rels: []string{"src_special/$"},
962 },
963 }
964
Colin Cross41955e82019-05-29 14:40:35 -0700965 testPathForModuleSrc(t, buildDir, tests)
966}
967
968func TestPathForModuleSrc(t *testing.T) {
969 buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
Colin Cross8a497952019-03-05 22:25:09 -0800970 if err != nil {
971 t.Fatal(err)
972 }
973 defer os.RemoveAll(buildDir)
974
Colin Cross8a497952019-03-05 22:25:09 -0800975 tests := []pathForModuleSrcTestCase{
976 {
977 name: "path",
978 bp: `
979 test {
980 name: "foo",
981 src: "src/b",
982 }`,
983 src: "foo/src/b",
984 rel: "src/b",
985 },
986 {
987 name: "glob",
988 bp: `
989 test {
990 name: "foo",
991 src: "src/e/*",
992 }`,
993 src: "foo/src/e/e",
994 rel: "src/e/e",
995 },
996 {
997 name: "filegroup",
998 bp: `
999 test {
1000 name: "foo",
1001 src: ":a",
1002 }`,
1003 src: "fg/src/a",
1004 rel: "src/a",
1005 },
1006 {
Colin Cross41955e82019-05-29 14:40:35 -07001007 name: "output file provider",
1008 bp: `
1009 test {
1010 name: "foo",
1011 src: ":b",
1012 }`,
1013 src: buildDir + "/.intermediates/ofp/b/gen/b",
1014 rel: "gen/b",
1015 },
1016 {
1017 name: "output file provider tagged",
1018 bp: `
1019 test {
1020 name: "foo",
1021 src: ":b{.tagged}",
1022 }`,
1023 src: buildDir + "/.intermediates/ofp/b/gen/c",
1024 rel: "gen/c",
1025 },
1026 {
Colin Cross8a497952019-03-05 22:25:09 -08001027 name: "special characters glob",
1028 bp: `
1029 test {
1030 name: "foo",
1031 src: "src_special/*",
1032 }`,
1033 src: "foo/src_special/$",
1034 rel: "src_special/$",
1035 },
1036 }
1037
Colin Cross8a497952019-03-05 22:25:09 -08001038 testPathForModuleSrc(t, buildDir, tests)
1039}
Colin Cross937664a2019-03-06 10:17:32 -08001040
Colin Cross8a497952019-03-05 22:25:09 -08001041func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
1042 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test")
1043 if err != nil {
1044 t.Fatal(err)
Colin Cross937664a2019-03-06 10:17:32 -08001045 }
Colin Cross8a497952019-03-05 22:25:09 -08001046 defer os.RemoveAll(buildDir)
1047
1048 config := TestConfig(buildDir, nil)
1049 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
1050
1051 ctx := NewTestContext()
1052 ctx.SetAllowMissingDependencies(true)
1053
1054 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
1055
1056 bp := `
1057 test {
1058 name: "foo",
1059 srcs: [":a"],
1060 exclude_srcs: [":b"],
1061 src: ":c",
1062 }
Colin Crossba71a3f2019-03-18 12:12:48 -07001063
1064 test {
1065 name: "bar",
1066 srcs: [":d"],
1067 exclude_srcs: [":e"],
1068 module_handles_missing_deps: true,
1069 }
Colin Cross8a497952019-03-05 22:25:09 -08001070 `
1071
1072 mockFS := map[string][]byte{
1073 "Android.bp": []byte(bp),
1074 }
1075
1076 ctx.MockFileSystem(mockFS)
1077
1078 ctx.Register()
1079 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
1080 FailIfErrored(t, errs)
1081 _, errs = ctx.PrepareBuildActions(config)
1082 FailIfErrored(t, errs)
1083
1084 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
1085
1086 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001087 t.Errorf("want foo missing deps %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001088 }
1089
1090 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
Colin Crossba71a3f2019-03-18 12:12:48 -07001091 t.Errorf("want foo srcs %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001092 }
1093
1094 if g, w := foo.src, ""; g != w {
Colin Crossba71a3f2019-03-18 12:12:48 -07001095 t.Errorf("want foo src %q, got %q", w, g)
Colin Cross8a497952019-03-05 22:25:09 -08001096 }
1097
Colin Crossba71a3f2019-03-18 12:12:48 -07001098 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1099
1100 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1101 t.Errorf("want bar missing deps %q, got %q", w, g)
1102 }
1103
1104 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1105 t.Errorf("want bar srcs %q, got %q", w, g)
1106 }
Colin Cross937664a2019-03-06 10:17:32 -08001107}
1108
Colin Cross8854a5a2019-02-11 14:14:16 -08001109func ExampleOutputPath_ReplaceExtension() {
1110 ctx := &configErrorWrapper{
1111 config: TestConfig("out", nil),
1112 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001113 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross8854a5a2019-02-11 14:14:16 -08001114 p2 := p.ReplaceExtension(ctx, "oat")
1115 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001116 fmt.Println(p.Rel(), p2.Rel())
Colin Cross8854a5a2019-02-11 14:14:16 -08001117
1118 // Output:
1119 // out/system/framework/boot.art out/system/framework/boot.oat
Colin Cross2cdd5df2019-02-25 10:25:24 -08001120 // boot.art boot.oat
Colin Cross8854a5a2019-02-11 14:14:16 -08001121}
Colin Cross40e33732019-02-15 11:08:35 -08001122
1123func ExampleOutputPath_FileInSameDir() {
1124 ctx := &configErrorWrapper{
1125 config: TestConfig("out", nil),
1126 }
Colin Cross2cdd5df2019-02-25 10:25:24 -08001127 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
Colin Cross40e33732019-02-15 11:08:35 -08001128 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1129 fmt.Println(p, p2)
Colin Cross2cdd5df2019-02-25 10:25:24 -08001130 fmt.Println(p.Rel(), p2.Rel())
Colin Cross40e33732019-02-15 11:08:35 -08001131
1132 // Output:
1133 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
Colin Cross2cdd5df2019-02-25 10:25:24 -08001134 // boot.art oat/arm/boot.vdex
Colin Cross40e33732019-02-15 11:08:35 -08001135}