blob: 1e4ba538c320b7c7941532cbdff28a9f89cefaa2 [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,
249 vendor: true,
250 },
251 },
252 in: []string{"bin", "my_test"},
253 out: "target/product/test_device/vendor/bin/my_test",
254 },
255
256 {
257 name: "system native test binary",
258 ctx: &moduleInstallPathContextImpl{
259 androidBaseContextImpl: androidBaseContextImpl{
260 target: deviceTarget,
261 },
262 inData: true,
263 },
264 in: []string{"nativetest", "my_test"},
265 out: "target/product/test_device/data/nativetest/my_test",
266 },
267 {
268 name: "vendor native test binary",
269 ctx: &moduleInstallPathContextImpl{
270 androidBaseContextImpl: androidBaseContextImpl{
271 target: deviceTarget,
272 vendor: true,
273 },
274 inData: true,
275 },
276 in: []string{"nativetest", "my_test"},
277 out: "target/product/test_device/data/nativetest/my_test",
278 },
279
280 {
281 name: "sanitized system binary",
282 ctx: &moduleInstallPathContextImpl{
283 androidBaseContextImpl: androidBaseContextImpl{
284 target: deviceTarget,
285 },
286 inSanitizerDir: true,
287 },
288 in: []string{"bin", "my_test"},
289 out: "target/product/test_device/data/asan/system/bin/my_test",
290 },
291 {
292 name: "sanitized vendor binary",
293 ctx: &moduleInstallPathContextImpl{
294 androidBaseContextImpl: androidBaseContextImpl{
295 target: deviceTarget,
296 vendor: true,
297 },
298 inSanitizerDir: true,
299 },
300 in: []string{"bin", "my_test"},
301 out: "target/product/test_device/data/asan/vendor/bin/my_test",
302 },
303
304 {
305 name: "sanitized system native test binary",
306 ctx: &moduleInstallPathContextImpl{
307 androidBaseContextImpl: androidBaseContextImpl{
308 target: deviceTarget,
309 },
310 inData: true,
311 inSanitizerDir: true,
312 },
313 in: []string{"nativetest", "my_test"},
314 out: "target/product/test_device/data/asan/data/nativetest/my_test",
315 },
316 {
317 name: "sanitized vendor native test binary",
318 ctx: &moduleInstallPathContextImpl{
319 androidBaseContextImpl: androidBaseContextImpl{
320 target: deviceTarget,
321 vendor: true,
322 },
323 inData: true,
324 inSanitizerDir: true,
325 },
326 in: []string{"nativetest", "my_test"},
327 out: "target/product/test_device/data/asan/data/nativetest/my_test",
328 },
329 }
330
331 for _, tc := range testCases {
332 t.Run(tc.name, func(t *testing.T) {
333 tc.ctx.androidBaseContextImpl.config = testConfig
334 output := PathForModuleInstall(tc.ctx, tc.in...)
335 if output.basePath.path != tc.out {
336 t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
337 output.basePath.path,
338 tc.out)
339 }
340 })
341 }
342}
Colin Cross5e6cfbe2017-11-03 15:20:35 -0700343
344func TestDirectorySortedPaths(t *testing.T) {
345 makePaths := func() Paths {
346 return Paths{
347 PathForTesting("a.txt"),
348 PathForTesting("a/txt"),
349 PathForTesting("a/b/c"),
350 PathForTesting("a/b/d"),
351 PathForTesting("b"),
352 PathForTesting("b/b.txt"),
353 PathForTesting("a/a.txt"),
354 }
355 }
356
357 expected := []string{
358 "a.txt",
359 "a/a.txt",
360 "a/b/c",
361 "a/b/d",
362 "a/txt",
363 "b",
364 "b/b.txt",
365 }
366
367 paths := makePaths()
368 reversePaths := make(Paths, len(paths))
369 for i, v := range paths {
370 reversePaths[len(paths)-i-1] = v
371 }
372
373 sortedPaths := PathsToDirectorySortedPaths(paths)
374 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
375
376 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
377 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
378 }
379
380 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
381 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
382 }
383
384 expectedA := []string{
385 "a/a.txt",
386 "a/b/c",
387 "a/b/d",
388 "a/txt",
389 }
390
391 inA := sortedPaths.PathsInDirectory("a")
392 if !reflect.DeepEqual(inA.Strings(), expectedA) {
393 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
394 }
395
396 expectedA_B := []string{
397 "a/b/c",
398 "a/b/d",
399 }
400
401 inA_B := sortedPaths.PathsInDirectory("a/b")
402 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
403 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
404 }
405
406 expectedB := []string{
407 "b/b.txt",
408 }
409
410 inB := sortedPaths.PathsInDirectory("b")
411 if !reflect.DeepEqual(inB.Strings(), expectedB) {
412 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
413 }
414}