blob: 00757985bd89beec41dd86d2ad773d833f923f91 [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
204}
205
206func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
207 return pathtools.MockFs(nil)
208}
209
Colin Crossaabf6792017-11-29 00:27:14 -0800210func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700211 return m.androidBaseContextImpl.config
212}
213
214func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
215
216func (m moduleInstallPathContextImpl) InstallInData() bool {
217 return m.inData
218}
219
220func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
221 return m.inSanitizerDir
222}
223
224func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700225 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700226
227 hostTarget := Target{Os: Linux}
228 deviceTarget := Target{Os: Android}
229
230 testCases := []struct {
231 name string
232 ctx *moduleInstallPathContextImpl
233 in []string
234 out string
235 }{
236 {
237 name: "host binary",
238 ctx: &moduleInstallPathContextImpl{
239 androidBaseContextImpl: androidBaseContextImpl{
240 target: hostTarget,
241 },
242 },
243 in: []string{"bin", "my_test"},
244 out: "host/linux-x86/bin/my_test",
245 },
246
247 {
248 name: "system binary",
249 ctx: &moduleInstallPathContextImpl{
250 androidBaseContextImpl: androidBaseContextImpl{
251 target: deviceTarget,
252 },
253 },
254 in: []string{"bin", "my_test"},
255 out: "target/product/test_device/system/bin/my_test",
256 },
257 {
258 name: "vendor binary",
259 ctx: &moduleInstallPathContextImpl{
260 androidBaseContextImpl: androidBaseContextImpl{
261 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900262 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700263 },
264 },
265 in: []string{"bin", "my_test"},
266 out: "target/product/test_device/vendor/bin/my_test",
267 },
Jiyong Park2db76922017-11-08 16:03:48 +0900268 {
269 name: "odm binary",
270 ctx: &moduleInstallPathContextImpl{
271 androidBaseContextImpl: androidBaseContextImpl{
272 target: deviceTarget,
273 kind: deviceSpecificModule,
274 },
275 },
276 in: []string{"bin", "my_test"},
277 out: "target/product/test_device/odm/bin/my_test",
278 },
279 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900280 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900281 ctx: &moduleInstallPathContextImpl{
282 androidBaseContextImpl: androidBaseContextImpl{
283 target: deviceTarget,
284 kind: productSpecificModule,
285 },
286 },
287 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900288 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900289 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700290
291 {
292 name: "system native test binary",
293 ctx: &moduleInstallPathContextImpl{
294 androidBaseContextImpl: androidBaseContextImpl{
295 target: deviceTarget,
296 },
297 inData: true,
298 },
299 in: []string{"nativetest", "my_test"},
300 out: "target/product/test_device/data/nativetest/my_test",
301 },
302 {
303 name: "vendor native test binary",
304 ctx: &moduleInstallPathContextImpl{
305 androidBaseContextImpl: androidBaseContextImpl{
306 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900307 kind: socSpecificModule,
308 },
309 inData: true,
310 },
311 in: []string{"nativetest", "my_test"},
312 out: "target/product/test_device/data/nativetest/my_test",
313 },
314 {
315 name: "odm native test binary",
316 ctx: &moduleInstallPathContextImpl{
317 androidBaseContextImpl: androidBaseContextImpl{
318 target: deviceTarget,
319 kind: deviceSpecificModule,
320 },
321 inData: true,
322 },
323 in: []string{"nativetest", "my_test"},
324 out: "target/product/test_device/data/nativetest/my_test",
325 },
326 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900327 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900328 ctx: &moduleInstallPathContextImpl{
329 androidBaseContextImpl: androidBaseContextImpl{
330 target: deviceTarget,
331 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700332 },
333 inData: true,
334 },
335 in: []string{"nativetest", "my_test"},
336 out: "target/product/test_device/data/nativetest/my_test",
337 },
338
339 {
340 name: "sanitized system binary",
341 ctx: &moduleInstallPathContextImpl{
342 androidBaseContextImpl: androidBaseContextImpl{
343 target: deviceTarget,
344 },
345 inSanitizerDir: true,
346 },
347 in: []string{"bin", "my_test"},
348 out: "target/product/test_device/data/asan/system/bin/my_test",
349 },
350 {
351 name: "sanitized vendor binary",
352 ctx: &moduleInstallPathContextImpl{
353 androidBaseContextImpl: androidBaseContextImpl{
354 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900355 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700356 },
357 inSanitizerDir: true,
358 },
359 in: []string{"bin", "my_test"},
360 out: "target/product/test_device/data/asan/vendor/bin/my_test",
361 },
Jiyong Park2db76922017-11-08 16:03:48 +0900362 {
363 name: "sanitized odm binary",
364 ctx: &moduleInstallPathContextImpl{
365 androidBaseContextImpl: androidBaseContextImpl{
366 target: deviceTarget,
367 kind: deviceSpecificModule,
368 },
369 inSanitizerDir: true,
370 },
371 in: []string{"bin", "my_test"},
372 out: "target/product/test_device/data/asan/odm/bin/my_test",
373 },
374 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900375 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900376 ctx: &moduleInstallPathContextImpl{
377 androidBaseContextImpl: androidBaseContextImpl{
378 target: deviceTarget,
379 kind: productSpecificModule,
380 },
381 inSanitizerDir: true,
382 },
383 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900384 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900385 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700386
387 {
388 name: "sanitized system native test binary",
389 ctx: &moduleInstallPathContextImpl{
390 androidBaseContextImpl: androidBaseContextImpl{
391 target: deviceTarget,
392 },
393 inData: true,
394 inSanitizerDir: true,
395 },
396 in: []string{"nativetest", "my_test"},
397 out: "target/product/test_device/data/asan/data/nativetest/my_test",
398 },
399 {
400 name: "sanitized vendor native test binary",
401 ctx: &moduleInstallPathContextImpl{
402 androidBaseContextImpl: androidBaseContextImpl{
403 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900404 kind: socSpecificModule,
405 },
406 inData: true,
407 inSanitizerDir: true,
408 },
409 in: []string{"nativetest", "my_test"},
410 out: "target/product/test_device/data/asan/data/nativetest/my_test",
411 },
412 {
413 name: "sanitized odm native test binary",
414 ctx: &moduleInstallPathContextImpl{
415 androidBaseContextImpl: androidBaseContextImpl{
416 target: deviceTarget,
417 kind: deviceSpecificModule,
418 },
419 inData: true,
420 inSanitizerDir: true,
421 },
422 in: []string{"nativetest", "my_test"},
423 out: "target/product/test_device/data/asan/data/nativetest/my_test",
424 },
425 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900426 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900427 ctx: &moduleInstallPathContextImpl{
428 androidBaseContextImpl: androidBaseContextImpl{
429 target: deviceTarget,
430 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700431 },
432 inData: true,
433 inSanitizerDir: true,
434 },
435 in: []string{"nativetest", "my_test"},
436 out: "target/product/test_device/data/asan/data/nativetest/my_test",
437 },
438 }
439
440 for _, tc := range testCases {
441 t.Run(tc.name, func(t *testing.T) {
442 tc.ctx.androidBaseContextImpl.config = testConfig
443 output := PathForModuleInstall(tc.ctx, tc.in...)
444 if output.basePath.path != tc.out {
445 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
446 output.basePath.path,
447 tc.out)
448 }
449 })
450 }
451}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700452
453func TestDirectorySortedPaths(t *testing.T) {
454 makePaths := func() Paths {
455 return Paths{
456 PathForTesting("a.txt"),
457 PathForTesting("a/txt"),
458 PathForTesting("a/b/c"),
459 PathForTesting("a/b/d"),
460 PathForTesting("b"),
461 PathForTesting("b/b.txt"),
462 PathForTesting("a/a.txt"),
463 }
464 }
465
466 expected := []string{
467 "a.txt",
468 "a/a.txt",
469 "a/b/c",
470 "a/b/d",
471 "a/txt",
472 "b",
473 "b/b.txt",
474 }
475
476 paths := makePaths()
477 reversePaths := make(Paths, len(paths))
478 for i, v := range paths {
479 reversePaths[len(paths)-i-1] = v
480 }
481
482 sortedPaths := PathsToDirectorySortedPaths(paths)
483 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
484
485 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
486 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
487 }
488
489 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
490 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
491 }
492
493 expectedA := []string{
494 "a/a.txt",
495 "a/b/c",
496 "a/b/d",
497 "a/txt",
498 }
499
500 inA := sortedPaths.PathsInDirectory("a")
501 if !reflect.DeepEqual(inA.Strings(), expectedA) {
502 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
503 }
504
505 expectedA_B := []string{
506 "a/b/c",
507 "a/b/d",
508 }
509
510 inA_B := sortedPaths.PathsInDirectory("a/b")
511 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
512 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
513 }
514
515 expectedB := []string{
516 "b/b.txt",
517 }
518
519 inB := sortedPaths.PathsInDirectory("b")
520 if !reflect.DeepEqual(inB.Strings(), expectedB) {
521 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
522 }
523}