blob: b3dc9de28fa55701fec6b5522d4e421490c87bdc [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"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070025)
26
27type strsTestCase struct {
28 in []string
29 out string
30 err []error
31}
32
33var commonValidatePathTestCases = []strsTestCase{
34 {
35 in: []string{""},
36 out: "",
37 },
38 {
39 in: []string{"a/b"},
40 out: "a/b",
41 },
42 {
43 in: []string{"a/b", "c"},
44 out: "a/b/c",
45 },
46 {
47 in: []string{"a/.."},
48 out: ".",
49 },
50 {
51 in: []string{"."},
52 out: ".",
53 },
54 {
55 in: []string{".."},
56 out: "",
57 err: []error{errors.New("Path is outside directory: ..")},
58 },
59 {
60 in: []string{"../a"},
61 out: "",
62 err: []error{errors.New("Path is outside directory: ../a")},
63 },
64 {
65 in: []string{"b/../../a"},
66 out: "",
67 err: []error{errors.New("Path is outside directory: ../a")},
68 },
69 {
70 in: []string{"/a"},
71 out: "",
72 err: []error{errors.New("Path is outside directory: /a")},
73 },
Dan Willemsen80a7c2a2015-12-21 14:57:11 -080074 {
75 in: []string{"a", "../b"},
76 out: "",
77 err: []error{errors.New("Path is outside directory: ../b")},
78 },
79 {
80 in: []string{"a", "b/../../c"},
81 out: "",
82 err: []error{errors.New("Path is outside directory: ../c")},
83 },
84 {
85 in: []string{"a", "./.."},
86 out: "",
87 err: []error{errors.New("Path is outside directory: ..")},
88 },
Dan Willemsen34cc69e2015-09-23 15:26:20 -070089}
90
91var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
92 {
93 in: []string{"$host/../$a"},
94 out: "$a",
95 },
96}...)
97
98var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
99 {
100 in: []string{"$host/../$a"},
101 out: "",
102 err: []error{errors.New("Path contains invalid character($): $host/../$a")},
103 },
104 {
105 in: []string{"$host/.."},
106 out: "",
107 err: []error{errors.New("Path contains invalid character($): $host/..")},
108 },
109}...)
110
111func TestValidateSafePath(t *testing.T) {
112 for _, testCase := range validateSafePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800113 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
114 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800115 out, err := validateSafePath(testCase.in...)
116 if err != nil {
117 reportPathError(ctx, err)
118 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800119 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
120 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700121 }
122}
123
124func TestValidatePath(t *testing.T) {
125 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800126 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
127 ctx := &configErrorWrapper{}
Colin Cross1ccfcc32018-02-22 13:54:26 -0800128 out, err := validatePath(testCase.in...)
129 if err != nil {
130 reportPathError(ctx, err)
131 }
Colin Crossdc75ae72018-02-22 13:48:13 -0800132 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
133 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700134 }
135}
136
137func TestOptionalPath(t *testing.T) {
138 var path OptionalPath
139 checkInvalidOptionalPath(t, path)
140
141 path = OptionalPathForPath(nil)
142 checkInvalidOptionalPath(t, path)
143}
144
145func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800146 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700147 if path.Valid() {
148 t.Errorf("Uninitialized OptionalPath should not be valid")
149 }
150 if path.String() != "" {
151 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
152 }
153 defer func() {
154 if r := recover(); r == nil {
155 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
156 }
157 }()
158 path.Path()
159}
160
161func check(t *testing.T, testType, testString string,
162 got interface{}, err []error,
163 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800164 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700165
166 printedTestCase := false
167 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800168 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700169 if !printedTestCase {
170 t.Errorf("test case %s: %s", testType, testString)
171 printedTestCase = true
172 }
173 t.Errorf("incorrect %s", s)
174 t.Errorf(" expected: %s", p(expected))
175 t.Errorf(" got: %s", p(got))
176 }
177
178 if !reflect.DeepEqual(expectedErr, err) {
179 e("errors:", expectedErr, err)
180 }
181
182 if !reflect.DeepEqual(expected, got) {
183 e("output:", expected, got)
184 }
185}
186
187func p(in interface{}) string {
188 if v, ok := in.([]interface{}); ok {
189 s := make([]string, len(v))
190 for i := range v {
191 s[i] = fmt.Sprintf("%#v", v[i])
192 }
193 return "[" + strings.Join(s, ", ") + "]"
194 } else {
195 return fmt.Sprintf("%#v", in)
196 }
197}
Dan Willemsen00269f22017-07-06 16:59:48 -0700198
199type moduleInstallPathContextImpl struct {
200 androidBaseContextImpl
201
202 inData bool
203 inSanitizerDir bool
Jiyong Parkf9332f12018-02-01 00:54:12 +0900204 inRecovery bool
Dan Willemsen00269f22017-07-06 16:59:48 -0700205}
206
207func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
208 return pathtools.MockFs(nil)
209}
210
Colin Crossaabf6792017-11-29 00:27:14 -0800211func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700212 return m.androidBaseContextImpl.config
213}
214
215func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
216
217func (m moduleInstallPathContextImpl) InstallInData() bool {
218 return m.inData
219}
220
221func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
222 return m.inSanitizerDir
223}
224
Jiyong Parkf9332f12018-02-01 00:54:12 +0900225func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
226 return m.inRecovery
227}
228
Dan Willemsen00269f22017-07-06 16:59:48 -0700229func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700230 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700231
232 hostTarget := Target{Os: Linux}
233 deviceTarget := Target{Os: Android}
234
235 testCases := []struct {
236 name string
237 ctx *moduleInstallPathContextImpl
238 in []string
239 out string
240 }{
241 {
242 name: "host binary",
243 ctx: &moduleInstallPathContextImpl{
244 androidBaseContextImpl: androidBaseContextImpl{
245 target: hostTarget,
246 },
247 },
248 in: []string{"bin", "my_test"},
249 out: "host/linux-x86/bin/my_test",
250 },
251
252 {
253 name: "system binary",
254 ctx: &moduleInstallPathContextImpl{
255 androidBaseContextImpl: androidBaseContextImpl{
256 target: deviceTarget,
257 },
258 },
259 in: []string{"bin", "my_test"},
260 out: "target/product/test_device/system/bin/my_test",
261 },
262 {
263 name: "vendor binary",
264 ctx: &moduleInstallPathContextImpl{
265 androidBaseContextImpl: androidBaseContextImpl{
266 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900267 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700268 },
269 },
270 in: []string{"bin", "my_test"},
271 out: "target/product/test_device/vendor/bin/my_test",
272 },
Jiyong Park2db76922017-11-08 16:03:48 +0900273 {
274 name: "odm binary",
275 ctx: &moduleInstallPathContextImpl{
276 androidBaseContextImpl: androidBaseContextImpl{
277 target: deviceTarget,
278 kind: deviceSpecificModule,
279 },
280 },
281 in: []string{"bin", "my_test"},
282 out: "target/product/test_device/odm/bin/my_test",
283 },
284 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900285 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900286 ctx: &moduleInstallPathContextImpl{
287 androidBaseContextImpl: androidBaseContextImpl{
288 target: deviceTarget,
289 kind: productSpecificModule,
290 },
291 },
292 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900293 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900294 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700295
296 {
297 name: "system native test binary",
298 ctx: &moduleInstallPathContextImpl{
299 androidBaseContextImpl: androidBaseContextImpl{
300 target: deviceTarget,
301 },
302 inData: true,
303 },
304 in: []string{"nativetest", "my_test"},
305 out: "target/product/test_device/data/nativetest/my_test",
306 },
307 {
308 name: "vendor native test binary",
309 ctx: &moduleInstallPathContextImpl{
310 androidBaseContextImpl: androidBaseContextImpl{
311 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900312 kind: socSpecificModule,
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: "odm native test binary",
321 ctx: &moduleInstallPathContextImpl{
322 androidBaseContextImpl: androidBaseContextImpl{
323 target: deviceTarget,
324 kind: deviceSpecificModule,
325 },
326 inData: true,
327 },
328 in: []string{"nativetest", "my_test"},
329 out: "target/product/test_device/data/nativetest/my_test",
330 },
331 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900332 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900333 ctx: &moduleInstallPathContextImpl{
334 androidBaseContextImpl: androidBaseContextImpl{
335 target: deviceTarget,
336 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700337 },
338 inData: true,
339 },
340 in: []string{"nativetest", "my_test"},
341 out: "target/product/test_device/data/nativetest/my_test",
342 },
343
344 {
345 name: "sanitized system binary",
346 ctx: &moduleInstallPathContextImpl{
347 androidBaseContextImpl: androidBaseContextImpl{
348 target: deviceTarget,
349 },
350 inSanitizerDir: true,
351 },
352 in: []string{"bin", "my_test"},
353 out: "target/product/test_device/data/asan/system/bin/my_test",
354 },
355 {
356 name: "sanitized vendor binary",
357 ctx: &moduleInstallPathContextImpl{
358 androidBaseContextImpl: androidBaseContextImpl{
359 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900360 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700361 },
362 inSanitizerDir: true,
363 },
364 in: []string{"bin", "my_test"},
365 out: "target/product/test_device/data/asan/vendor/bin/my_test",
366 },
Jiyong Park2db76922017-11-08 16:03:48 +0900367 {
368 name: "sanitized odm binary",
369 ctx: &moduleInstallPathContextImpl{
370 androidBaseContextImpl: androidBaseContextImpl{
371 target: deviceTarget,
372 kind: deviceSpecificModule,
373 },
374 inSanitizerDir: true,
375 },
376 in: []string{"bin", "my_test"},
377 out: "target/product/test_device/data/asan/odm/bin/my_test",
378 },
379 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900380 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900381 ctx: &moduleInstallPathContextImpl{
382 androidBaseContextImpl: androidBaseContextImpl{
383 target: deviceTarget,
384 kind: productSpecificModule,
385 },
386 inSanitizerDir: true,
387 },
388 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900389 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900390 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700391
392 {
393 name: "sanitized system native test binary",
394 ctx: &moduleInstallPathContextImpl{
395 androidBaseContextImpl: androidBaseContextImpl{
396 target: deviceTarget,
397 },
398 inData: true,
399 inSanitizerDir: true,
400 },
401 in: []string{"nativetest", "my_test"},
402 out: "target/product/test_device/data/asan/data/nativetest/my_test",
403 },
404 {
405 name: "sanitized vendor native test binary",
406 ctx: &moduleInstallPathContextImpl{
407 androidBaseContextImpl: androidBaseContextImpl{
408 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900409 kind: socSpecificModule,
410 },
411 inData: true,
412 inSanitizerDir: true,
413 },
414 in: []string{"nativetest", "my_test"},
415 out: "target/product/test_device/data/asan/data/nativetest/my_test",
416 },
417 {
418 name: "sanitized odm native test binary",
419 ctx: &moduleInstallPathContextImpl{
420 androidBaseContextImpl: androidBaseContextImpl{
421 target: deviceTarget,
422 kind: deviceSpecificModule,
423 },
424 inData: true,
425 inSanitizerDir: true,
426 },
427 in: []string{"nativetest", "my_test"},
428 out: "target/product/test_device/data/asan/data/nativetest/my_test",
429 },
430 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900431 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900432 ctx: &moduleInstallPathContextImpl{
433 androidBaseContextImpl: androidBaseContextImpl{
434 target: deviceTarget,
435 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700436 },
437 inData: true,
438 inSanitizerDir: true,
439 },
440 in: []string{"nativetest", "my_test"},
441 out: "target/product/test_device/data/asan/data/nativetest/my_test",
442 },
443 }
444
445 for _, tc := range testCases {
446 t.Run(tc.name, func(t *testing.T) {
447 tc.ctx.androidBaseContextImpl.config = testConfig
448 output := PathForModuleInstall(tc.ctx, tc.in...)
449 if output.basePath.path != tc.out {
450 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
451 output.basePath.path,
452 tc.out)
453 }
454 })
455 }
456}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700457
458func TestDirectorySortedPaths(t *testing.T) {
459 makePaths := func() Paths {
460 return Paths{
461 PathForTesting("a.txt"),
462 PathForTesting("a/txt"),
463 PathForTesting("a/b/c"),
464 PathForTesting("a/b/d"),
465 PathForTesting("b"),
466 PathForTesting("b/b.txt"),
467 PathForTesting("a/a.txt"),
468 }
469 }
470
471 expected := []string{
472 "a.txt",
473 "a/a.txt",
474 "a/b/c",
475 "a/b/d",
476 "a/txt",
477 "b",
478 "b/b.txt",
479 }
480
481 paths := makePaths()
Colin Crossa140bb02018-04-17 10:52:26 -0700482 reversePaths := ReversePaths(paths)
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700483
484 sortedPaths := PathsToDirectorySortedPaths(paths)
485 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
486
487 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
488 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
489 }
490
491 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
492 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
493 }
494
495 expectedA := []string{
496 "a/a.txt",
497 "a/b/c",
498 "a/b/d",
499 "a/txt",
500 }
501
502 inA := sortedPaths.PathsInDirectory("a")
503 if !reflect.DeepEqual(inA.Strings(), expectedA) {
504 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
505 }
506
507 expectedA_B := []string{
508 "a/b/c",
509 "a/b/d",
510 }
511
512 inA_B := sortedPaths.PathsInDirectory("a/b")
513 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
514 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
515 }
516
517 expectedB := []string{
518 "b/b.txt",
519 }
520
521 inB := sortedPaths.PathsInDirectory("b")
522 if !reflect.DeepEqual(inB.Strings(), expectedB) {
523 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
524 }
525}