blob: 61a172fa091abac0284611a536351c78e6f8305b [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 {
113 ctx := &configErrorWrapper{}
114 out := validateSafePath(ctx, testCase.in...)
115 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
116 }
117}
118
119func TestValidatePath(t *testing.T) {
120 for _, testCase := range validatePathTestCases {
121 ctx := &configErrorWrapper{}
122 out := validatePath(ctx, testCase.in...)
123 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
124 }
125}
126
127func TestOptionalPath(t *testing.T) {
128 var path OptionalPath
129 checkInvalidOptionalPath(t, path)
130
131 path = OptionalPathForPath(nil)
132 checkInvalidOptionalPath(t, path)
133}
134
135func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
136 if path.Valid() {
137 t.Errorf("Uninitialized OptionalPath should not be valid")
138 }
139 if path.String() != "" {
140 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
141 }
142 defer func() {
143 if r := recover(); r == nil {
144 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
145 }
146 }()
147 path.Path()
148}
149
150func check(t *testing.T, testType, testString string,
151 got interface{}, err []error,
152 expected interface{}, expectedErr []error) {
153
154 printedTestCase := false
155 e := func(s string, expected, got interface{}) {
156 if !printedTestCase {
157 t.Errorf("test case %s: %s", testType, testString)
158 printedTestCase = true
159 }
160 t.Errorf("incorrect %s", s)
161 t.Errorf(" expected: %s", p(expected))
162 t.Errorf(" got: %s", p(got))
163 }
164
165 if !reflect.DeepEqual(expectedErr, err) {
166 e("errors:", expectedErr, err)
167 }
168
169 if !reflect.DeepEqual(expected, got) {
170 e("output:", expected, got)
171 }
172}
173
174func p(in interface{}) string {
175 if v, ok := in.([]interface{}); ok {
176 s := make([]string, len(v))
177 for i := range v {
178 s[i] = fmt.Sprintf("%#v", v[i])
179 }
180 return "[" + strings.Join(s, ", ") + "]"
181 } else {
182 return fmt.Sprintf("%#v", in)
183 }
184}
Dan Willemsen00269f22017-07-06 16:59:48 -0700185
186type moduleInstallPathContextImpl struct {
187 androidBaseContextImpl
188
189 inData bool
190 inSanitizerDir bool
191}
192
193func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
194 return pathtools.MockFs(nil)
195}
196
Colin Crossaabf6792017-11-29 00:27:14 -0800197func (m moduleInstallPathContextImpl) Config() Config {
Dan Willemsen00269f22017-07-06 16:59:48 -0700198 return m.androidBaseContextImpl.config
199}
200
201func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
202
203func (m moduleInstallPathContextImpl) InstallInData() bool {
204 return m.inData
205}
206
207func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
208 return m.inSanitizerDir
209}
210
211func TestPathForModuleInstall(t *testing.T) {
Colin Cross6ccbc912017-10-10 23:07:38 -0700212 testConfig := TestConfig("", nil)
Dan Willemsen00269f22017-07-06 16:59:48 -0700213
214 hostTarget := Target{Os: Linux}
215 deviceTarget := Target{Os: Android}
216
217 testCases := []struct {
218 name string
219 ctx *moduleInstallPathContextImpl
220 in []string
221 out string
222 }{
223 {
224 name: "host binary",
225 ctx: &moduleInstallPathContextImpl{
226 androidBaseContextImpl: androidBaseContextImpl{
227 target: hostTarget,
228 },
229 },
230 in: []string{"bin", "my_test"},
231 out: "host/linux-x86/bin/my_test",
232 },
233
234 {
235 name: "system binary",
236 ctx: &moduleInstallPathContextImpl{
237 androidBaseContextImpl: androidBaseContextImpl{
238 target: deviceTarget,
239 },
240 },
241 in: []string{"bin", "my_test"},
242 out: "target/product/test_device/system/bin/my_test",
243 },
244 {
245 name: "vendor binary",
246 ctx: &moduleInstallPathContextImpl{
247 androidBaseContextImpl: androidBaseContextImpl{
248 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900249 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700250 },
251 },
252 in: []string{"bin", "my_test"},
253 out: "target/product/test_device/vendor/bin/my_test",
254 },
Jiyong Park2db76922017-11-08 16:03:48 +0900255 {
256 name: "odm binary",
257 ctx: &moduleInstallPathContextImpl{
258 androidBaseContextImpl: androidBaseContextImpl{
259 target: deviceTarget,
260 kind: deviceSpecificModule,
261 },
262 },
263 in: []string{"bin", "my_test"},
264 out: "target/product/test_device/odm/bin/my_test",
265 },
266 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900267 name: "product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900268 ctx: &moduleInstallPathContextImpl{
269 androidBaseContextImpl: androidBaseContextImpl{
270 target: deviceTarget,
271 kind: productSpecificModule,
272 },
273 },
274 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900275 out: "target/product/test_device/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900276 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700277
278 {
279 name: "system native test binary",
280 ctx: &moduleInstallPathContextImpl{
281 androidBaseContextImpl: androidBaseContextImpl{
282 target: deviceTarget,
283 },
284 inData: true,
285 },
286 in: []string{"nativetest", "my_test"},
287 out: "target/product/test_device/data/nativetest/my_test",
288 },
289 {
290 name: "vendor native test binary",
291 ctx: &moduleInstallPathContextImpl{
292 androidBaseContextImpl: androidBaseContextImpl{
293 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900294 kind: socSpecificModule,
295 },
296 inData: true,
297 },
298 in: []string{"nativetest", "my_test"},
299 out: "target/product/test_device/data/nativetest/my_test",
300 },
301 {
302 name: "odm native test binary",
303 ctx: &moduleInstallPathContextImpl{
304 androidBaseContextImpl: androidBaseContextImpl{
305 target: deviceTarget,
306 kind: deviceSpecificModule,
307 },
308 inData: true,
309 },
310 in: []string{"nativetest", "my_test"},
311 out: "target/product/test_device/data/nativetest/my_test",
312 },
313 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900314 name: "product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900315 ctx: &moduleInstallPathContextImpl{
316 androidBaseContextImpl: androidBaseContextImpl{
317 target: deviceTarget,
318 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700319 },
320 inData: true,
321 },
322 in: []string{"nativetest", "my_test"},
323 out: "target/product/test_device/data/nativetest/my_test",
324 },
325
326 {
327 name: "sanitized system binary",
328 ctx: &moduleInstallPathContextImpl{
329 androidBaseContextImpl: androidBaseContextImpl{
330 target: deviceTarget,
331 },
332 inSanitizerDir: true,
333 },
334 in: []string{"bin", "my_test"},
335 out: "target/product/test_device/data/asan/system/bin/my_test",
336 },
337 {
338 name: "sanitized vendor binary",
339 ctx: &moduleInstallPathContextImpl{
340 androidBaseContextImpl: androidBaseContextImpl{
341 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900342 kind: socSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700343 },
344 inSanitizerDir: true,
345 },
346 in: []string{"bin", "my_test"},
347 out: "target/product/test_device/data/asan/vendor/bin/my_test",
348 },
Jiyong Park2db76922017-11-08 16:03:48 +0900349 {
350 name: "sanitized odm binary",
351 ctx: &moduleInstallPathContextImpl{
352 androidBaseContextImpl: androidBaseContextImpl{
353 target: deviceTarget,
354 kind: deviceSpecificModule,
355 },
356 inSanitizerDir: true,
357 },
358 in: []string{"bin", "my_test"},
359 out: "target/product/test_device/data/asan/odm/bin/my_test",
360 },
361 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900362 name: "sanitized product binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900363 ctx: &moduleInstallPathContextImpl{
364 androidBaseContextImpl: androidBaseContextImpl{
365 target: deviceTarget,
366 kind: productSpecificModule,
367 },
368 inSanitizerDir: true,
369 },
370 in: []string{"bin", "my_test"},
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900371 out: "target/product/test_device/data/asan/product/bin/my_test",
Jiyong Park2db76922017-11-08 16:03:48 +0900372 },
Dan Willemsen00269f22017-07-06 16:59:48 -0700373
374 {
375 name: "sanitized system native test binary",
376 ctx: &moduleInstallPathContextImpl{
377 androidBaseContextImpl: androidBaseContextImpl{
378 target: deviceTarget,
379 },
380 inData: true,
381 inSanitizerDir: true,
382 },
383 in: []string{"nativetest", "my_test"},
384 out: "target/product/test_device/data/asan/data/nativetest/my_test",
385 },
386 {
387 name: "sanitized vendor native test binary",
388 ctx: &moduleInstallPathContextImpl{
389 androidBaseContextImpl: androidBaseContextImpl{
390 target: deviceTarget,
Jiyong Park2db76922017-11-08 16:03:48 +0900391 kind: socSpecificModule,
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 odm native test binary",
401 ctx: &moduleInstallPathContextImpl{
402 androidBaseContextImpl: androidBaseContextImpl{
403 target: deviceTarget,
404 kind: deviceSpecificModule,
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 {
Jaekyun Seok5cfbfbb2018-01-10 19:00:15 +0900413 name: "sanitized product native test binary",
Jiyong Park2db76922017-11-08 16:03:48 +0900414 ctx: &moduleInstallPathContextImpl{
415 androidBaseContextImpl: androidBaseContextImpl{
416 target: deviceTarget,
417 kind: productSpecificModule,
Dan Willemsen00269f22017-07-06 16:59:48 -0700418 },
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 }
426
427 for _, tc := range testCases {
428 t.Run(tc.name, func(t *testing.T) {
429 tc.ctx.androidBaseContextImpl.config = testConfig
430 output := PathForModuleInstall(tc.ctx, tc.in...)
431 if output.basePath.path != tc.out {
432 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
433 output.basePath.path,
434 tc.out)
435 }
436 })
437 }
438}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700439
440func TestDirectorySortedPaths(t *testing.T) {
441 makePaths := func() Paths {
442 return Paths{
443 PathForTesting("a.txt"),
444 PathForTesting("a/txt"),
445 PathForTesting("a/b/c"),
446 PathForTesting("a/b/d"),
447 PathForTesting("b"),
448 PathForTesting("b/b.txt"),
449 PathForTesting("a/a.txt"),
450 }
451 }
452
453 expected := []string{
454 "a.txt",
455 "a/a.txt",
456 "a/b/c",
457 "a/b/d",
458 "a/txt",
459 "b",
460 "b/b.txt",
461 }
462
463 paths := makePaths()
464 reversePaths := make(Paths, len(paths))
465 for i, v := range paths {
466 reversePaths[len(paths)-i-1] = v
467 }
468
469 sortedPaths := PathsToDirectorySortedPaths(paths)
470 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
471
472 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
473 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
474 }
475
476 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
477 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
478 }
479
480 expectedA := []string{
481 "a/a.txt",
482 "a/b/c",
483 "a/b/d",
484 "a/txt",
485 }
486
487 inA := sortedPaths.PathsInDirectory("a")
488 if !reflect.DeepEqual(inA.Strings(), expectedA) {
489 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
490 }
491
492 expectedA_B := []string{
493 "a/b/c",
494 "a/b/d",
495 }
496
497 inA_B := sortedPaths.PathsInDirectory("a/b")
498 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
499 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
500 }
501
502 expectedB := []string{
503 "b/b.txt",
504 }
505
506 inB := sortedPaths.PathsInDirectory("b")
507 if !reflect.DeepEqual(inB.Strings(), expectedB) {
508 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
509 }
510}