blob: 7e7ecbdfdb492573c0087b97d472e87aad21ce5a [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{}
115 out := validateSafePath(ctx, testCase.in...)
116 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
117 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700118 }
119}
120
121func TestValidatePath(t *testing.T) {
122 for _, testCase := range validatePathTestCases {
Colin Crossdc75ae72018-02-22 13:48:13 -0800123 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
124 ctx := &configErrorWrapper{}
125 out := validatePath(ctx, testCase.in...)
126 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
127 })
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700128 }
129}
130
131func TestOptionalPath(t *testing.T) {
132 var path OptionalPath
133 checkInvalidOptionalPath(t, path)
134
135 path = OptionalPathForPath(nil)
136 checkInvalidOptionalPath(t, path)
137}
138
139func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800140 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700141 if path.Valid() {
142 t.Errorf("Uninitialized OptionalPath should not be valid")
143 }
144 if path.String() != "" {
145 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
146 }
147 defer func() {
148 if r := recover(); r == nil {
149 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
150 }
151 }()
152 path.Path()
153}
154
155func check(t *testing.T, testType, testString string,
156 got interface{}, err []error,
157 expected interface{}, expectedErr []error) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800158 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700159
160 printedTestCase := false
161 e := func(s string, expected, got interface{}) {
Colin Crossdc75ae72018-02-22 13:48:13 -0800162 t.Helper()
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700163 if !printedTestCase {
164 t.Errorf("test case %s: %s", testType, testString)
165 printedTestCase = true
166 }
167 t.Errorf("incorrect %s", s)
168 t.Errorf(" expected: %s", p(expected))
169 t.Errorf(" got: %s", p(got))
170 }
171
172 if !reflect.DeepEqual(expectedErr, err) {
173 e("errors:", expectedErr, err)
174 }
175
176 if !reflect.DeepEqual(expected, got) {
177 e("output:", expected, got)
178 }
179}
180
181func p(in interface{}) string {
182 if v, ok := in.([]interface{}); ok {
183 s := make([]string, len(v))
184 for i := range v {
185 s[i] = fmt.Sprintf("%#v", v[i])
186 }
187 return "[" + strings.Join(s, ", ") + "]"
188 } else {
189 return fmt.Sprintf("%#v", in)
190 }
191}
Dan Willemsen00269f22017-07-06 16:59:48 -0700192
193type moduleInstallPathContextImpl struct {
194 androidBaseContextImpl
195
196 inData bool
197 inSanitizerDir bool
198}
199
200func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
201 return pathtools.MockFs(nil)
202}
203
Colin Crossaabf6792017-11-29 00:27:14 -0800204func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700205 return m.androidBaseContextImpl.config
206}
207
208func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
209
210func (m moduleInstallPathContextImpl) InstallInData() bool {
211 return m.inData
212}
213
214func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
215 return m.inSanitizerDir
216}
217
218func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700219 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700220
221 hostTarget := Target{Os: Linux}
222 deviceTarget := Target{Os: Android}
223
224 testCases := []struct {
225 name string
226 ctx *moduleInstallPathContextImpl
227 in []string
228 out string
229 }{
230 {
231 name: "host binary",
232 ctx: &moduleInstallPathContextImpl{
233 androidBaseContextImpl: androidBaseContextImpl{
234 target: hostTarget,
235 },
236 },
237 in: []string{"bin", "my_test"},
238 out: "host/linux-x86/bin/my_test",
239 },
240
241 {
242 name: "system binary",
243 ctx: &moduleInstallPathContextImpl{
244 androidBaseContextImpl: androidBaseContextImpl{
245 target: deviceTarget,
246 },
247 },
248 in: []string{"bin", "my_test"},
249 out: "target/product/test_device/system/bin/my_test",
250 },
251 {
252 name: "vendor binary",
253 ctx: &moduleInstallPathContextImpl{
254 androidBaseContextImpl: androidBaseContextImpl{
255 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900256 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700257 },
258 },
259 in: []string{"bin", "my_test"},
260 out: "target/product/test_device/vendor/bin/my_test",
261 },
Jiyong Park2db76922017-11-08 16:03:48 +0900262 {
263 name: "odm binary",
264 ctx: &moduleInstallPathContextImpl{
265 androidBaseContextImpl: androidBaseContextImpl{
266 target: deviceTarget,
267 kind: deviceSpecificModule,
268 },
269 },
270 in: []string{"bin", "my_test"},
271 out: "target/product/test_device/odm/bin/my_test",
272 },
273 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900274 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900275 ctx: &moduleInstallPathContextImpl{
276 androidBaseContextImpl: androidBaseContextImpl{
277 target: deviceTarget,
278 kind: productSpecificModule,
279 },
280 },
281 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900282 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900283 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700284
285 {
286 name: "system native test binary",
287 ctx: &moduleInstallPathContextImpl{
288 androidBaseContextImpl: androidBaseContextImpl{
289 target: deviceTarget,
290 },
291 inData: true,
292 },
293 in: []string{"nativetest", "my_test"},
294 out: "target/product/test_device/data/nativetest/my_test",
295 },
296 {
297 name: "vendor native test binary",
298 ctx: &moduleInstallPathContextImpl{
299 androidBaseContextImpl: androidBaseContextImpl{
300 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900301 kind: socSpecificModule,
302 },
303 inData: true,
304 },
305 in: []string{"nativetest", "my_test"},
306 out: "target/product/test_device/data/nativetest/my_test",
307 },
308 {
309 name: "odm native test binary",
310 ctx: &moduleInstallPathContextImpl{
311 androidBaseContextImpl: androidBaseContextImpl{
312 target: deviceTarget,
313 kind: deviceSpecificModule,
314 },
315 inData: true,
316 },
317 in: []string{"nativetest", "my_test"},
318 out: "target/product/test_device/data/nativetest/my_test",
319 },
320 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900321 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900322 ctx: &moduleInstallPathContextImpl{
323 androidBaseContextImpl: androidBaseContextImpl{
324 target: deviceTarget,
325 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700326 },
327 inData: true,
328 },
329 in: []string{"nativetest", "my_test"},
330 out: "target/product/test_device/data/nativetest/my_test",
331 },
332
333 {
334 name: "sanitized system binary",
335 ctx: &moduleInstallPathContextImpl{
336 androidBaseContextImpl: androidBaseContextImpl{
337 target: deviceTarget,
338 },
339 inSanitizerDir: true,
340 },
341 in: []string{"bin", "my_test"},
342 out: "target/product/test_device/data/asan/system/bin/my_test",
343 },
344 {
345 name: "sanitized vendor binary",
346 ctx: &moduleInstallPathContextImpl{
347 androidBaseContextImpl: androidBaseContextImpl{
348 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900349 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700350 },
351 inSanitizerDir: true,
352 },
353 in: []string{"bin", "my_test"},
354 out: "target/product/test_device/data/asan/vendor/bin/my_test",
355 },
Jiyong Park2db76922017-11-08 16:03:48 +0900356 {
357 name: "sanitized odm binary",
358 ctx: &moduleInstallPathContextImpl{
359 androidBaseContextImpl: androidBaseContextImpl{
360 target: deviceTarget,
361 kind: deviceSpecificModule,
362 },
363 inSanitizerDir: true,
364 },
365 in: []string{"bin", "my_test"},
366 out: "target/product/test_device/data/asan/odm/bin/my_test",
367 },
368 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900369 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900370 ctx: &moduleInstallPathContextImpl{
371 androidBaseContextImpl: androidBaseContextImpl{
372 target: deviceTarget,
373 kind: productSpecificModule,
374 },
375 inSanitizerDir: true,
376 },
377 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900378 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900379 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700380
381 {
382 name: "sanitized system native test binary",
383 ctx: &moduleInstallPathContextImpl{
384 androidBaseContextImpl: androidBaseContextImpl{
385 target: deviceTarget,
386 },
387 inData: true,
388 inSanitizerDir: true,
389 },
390 in: []string{"nativetest", "my_test"},
391 out: "target/product/test_device/data/asan/data/nativetest/my_test",
392 },
393 {
394 name: "sanitized vendor native test binary",
395 ctx: &moduleInstallPathContextImpl{
396 androidBaseContextImpl: androidBaseContextImpl{
397 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900398 kind: socSpecificModule,
399 },
400 inData: true,
401 inSanitizerDir: true,
402 },
403 in: []string{"nativetest", "my_test"},
404 out: "target/product/test_device/data/asan/data/nativetest/my_test",
405 },
406 {
407 name: "sanitized odm native test binary",
408 ctx: &moduleInstallPathContextImpl{
409 androidBaseContextImpl: androidBaseContextImpl{
410 target: deviceTarget,
411 kind: deviceSpecificModule,
412 },
413 inData: true,
414 inSanitizerDir: true,
415 },
416 in: []string{"nativetest", "my_test"},
417 out: "target/product/test_device/data/asan/data/nativetest/my_test",
418 },
419 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900420 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900421 ctx: &moduleInstallPathContextImpl{
422 androidBaseContextImpl: androidBaseContextImpl{
423 target: deviceTarget,
424 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700425 },
426 inData: true,
427 inSanitizerDir: true,
428 },
429 in: []string{"nativetest", "my_test"},
430 out: "target/product/test_device/data/asan/data/nativetest/my_test",
431 },
432 }
433
434 for _, tc := range testCases {
435 t.Run(tc.name, func(t *testing.T) {
436 tc.ctx.androidBaseContextImpl.config = testConfig
437 output := PathForModuleInstall(tc.ctx, tc.in...)
438 if output.basePath.path != tc.out {
439 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
440 output.basePath.path,
441 tc.out)
442 }
443 })
444 }
445}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700446
447func TestDirectorySortedPaths(t *testing.T) {
448 makePaths := func() Paths {
449 return Paths{
450 PathForTesting("a.txt"),
451 PathForTesting("a/txt"),
452 PathForTesting("a/b/c"),
453 PathForTesting("a/b/d"),
454 PathForTesting("b"),
455 PathForTesting("b/b.txt"),
456 PathForTesting("a/a.txt"),
457 }
458 }
459
460 expected := []string{
461 "a.txt",
462 "a/a.txt",
463 "a/b/c",
464 "a/b/d",
465 "a/txt",
466 "b",
467 "b/b.txt",
468 }
469
470 paths := makePaths()
471 reversePaths := make(Paths, len(paths))
472 for i, v := range paths {
473 reversePaths[len(paths)-i-1] = v
474 }
475
476 sortedPaths := PathsToDirectorySortedPaths(paths)
477 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
478
479 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
480 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
481 }
482
483 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
484 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
485 }
486
487 expectedA := []string{
488 "a/a.txt",
489 "a/b/c",
490 "a/b/d",
491 "a/txt",
492 }
493
494 inA := sortedPaths.PathsInDirectory("a")
495 if !reflect.DeepEqual(inA.Strings(), expectedA) {
496 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
497 }
498
499 expectedA_B := []string{
500 "a/b/c",
501 "a/b/d",
502 }
503
504 inA_B := sortedPaths.PathsInDirectory("a/b")
505 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
506 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
507 }
508
509 expectedB := []string{
510 "b/b.txt",
511 }
512
513 inB := sortedPaths.PathsInDirectory("b")
514 if !reflect.DeepEqual(inB.Strings(), expectedB) {
515 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
516 }
517}