blob: 1f9ca361c5fa74d91f1cf97b6b504e90cd4fbad5 [file] [log] [blame]
Colin Crossb6715442017-10-24 11:13:31 -07001// Copyright 2017 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
15package android
16
17import (
Colin Cross454c0872019-02-15 23:03:34 -080018 "fmt"
Colin Crossb6715442017-10-24 11:13:31 -070019 "reflect"
20 "testing"
21)
22
23var firstUniqueStringsTestCases = []struct {
24 in []string
25 out []string
26}{
27 {
28 in: []string{"a"},
29 out: []string{"a"},
30 },
31 {
32 in: []string{"a", "b"},
33 out: []string{"a", "b"},
34 },
35 {
36 in: []string{"a", "a"},
37 out: []string{"a"},
38 },
39 {
40 in: []string{"a", "b", "a"},
41 out: []string{"a", "b"},
42 },
43 {
44 in: []string{"b", "a", "a"},
45 out: []string{"b", "a"},
46 },
47 {
48 in: []string{"a", "a", "b"},
49 out: []string{"a", "b"},
50 },
51 {
52 in: []string{"a", "b", "a", "b"},
53 out: []string{"a", "b"},
54 },
55 {
56 in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
57 out: []string{"liblog", "libdl", "libc++", "libc", "libm"},
58 },
59}
60
61func TestFirstUniqueStrings(t *testing.T) {
62 for _, testCase := range firstUniqueStringsTestCases {
63 out := FirstUniqueStrings(testCase.in)
64 if !reflect.DeepEqual(out, testCase.out) {
65 t.Errorf("incorrect output:")
66 t.Errorf(" input: %#v", testCase.in)
67 t.Errorf(" expected: %#v", testCase.out)
68 t.Errorf(" got: %#v", out)
69 }
70 }
71}
72
73var lastUniqueStringsTestCases = []struct {
74 in []string
75 out []string
76}{
77 {
78 in: []string{"a"},
79 out: []string{"a"},
80 },
81 {
82 in: []string{"a", "b"},
83 out: []string{"a", "b"},
84 },
85 {
86 in: []string{"a", "a"},
87 out: []string{"a"},
88 },
89 {
90 in: []string{"a", "b", "a"},
91 out: []string{"b", "a"},
92 },
93 {
94 in: []string{"b", "a", "a"},
95 out: []string{"b", "a"},
96 },
97 {
98 in: []string{"a", "a", "b"},
99 out: []string{"a", "b"},
100 },
101 {
102 in: []string{"a", "b", "a", "b"},
103 out: []string{"a", "b"},
104 },
105 {
106 in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
107 out: []string{"liblog", "libc++", "libdl", "libc", "libm"},
108 },
109}
110
111func TestLastUniqueStrings(t *testing.T) {
112 for _, testCase := range lastUniqueStringsTestCases {
113 out := LastUniqueStrings(testCase.in)
114 if !reflect.DeepEqual(out, testCase.out) {
115 t.Errorf("incorrect output:")
116 t.Errorf(" input: %#v", testCase.in)
117 t.Errorf(" expected: %#v", testCase.out)
118 t.Errorf(" got: %#v", out)
119 }
120 }
121}
Logan Chien5e877b12018-03-08 18:14:19 +0800122
123func TestJoinWithPrefix(t *testing.T) {
124 testcases := []struct {
125 name string
126 input []string
127 expected string
128 }{
129 {
130 name: "zero_inputs",
131 input: []string{},
132 expected: "",
133 },
134 {
135 name: "one_input",
136 input: []string{"a"},
137 expected: "prefix:a",
138 },
139 {
140 name: "two_inputs",
141 input: []string{"a", "b"},
142 expected: "prefix:a prefix:b",
143 },
144 }
145
146 prefix := "prefix:"
147
148 for _, testCase := range testcases {
149 t.Run(testCase.name, func(t *testing.T) {
150 out := JoinWithPrefix(testCase.input, prefix)
151 if out != testCase.expected {
152 t.Errorf("incorrect output:")
153 t.Errorf(" input: %#v", testCase.input)
154 t.Errorf(" prefix: %#v", prefix)
155 t.Errorf(" expected: %#v", testCase.expected)
156 t.Errorf(" got: %#v", out)
157 }
158 })
159 }
160}
161
162func TestIndexList(t *testing.T) {
163 input := []string{"a", "b", "c"}
164
165 testcases := []struct {
166 key string
167 expected int
168 }{
169 {
170 key: "a",
171 expected: 0,
172 },
173 {
174 key: "b",
175 expected: 1,
176 },
177 {
178 key: "c",
179 expected: 2,
180 },
181 {
182 key: "X",
183 expected: -1,
184 },
185 }
186
187 for _, testCase := range testcases {
188 t.Run(testCase.key, func(t *testing.T) {
189 out := IndexList(testCase.key, input)
190 if out != testCase.expected {
191 t.Errorf("incorrect output:")
192 t.Errorf(" key: %#v", testCase.key)
193 t.Errorf(" input: %#v", input)
194 t.Errorf(" expected: %#v", testCase.expected)
195 t.Errorf(" got: %#v", out)
196 }
197 })
198 }
199}
200
201func TestInList(t *testing.T) {
202 input := []string{"a"}
203
204 testcases := []struct {
205 key string
206 expected bool
207 }{
208 {
209 key: "a",
210 expected: true,
211 },
212 {
213 key: "X",
214 expected: false,
215 },
216 }
217
218 for _, testCase := range testcases {
219 t.Run(testCase.key, func(t *testing.T) {
220 out := InList(testCase.key, input)
221 if out != testCase.expected {
222 t.Errorf("incorrect output:")
223 t.Errorf(" key: %#v", testCase.key)
224 t.Errorf(" input: %#v", input)
225 t.Errorf(" expected: %#v", testCase.expected)
226 t.Errorf(" got: %#v", out)
227 }
228 })
229 }
230}
231
232func TestPrefixInList(t *testing.T) {
233 prefixes := []string{"a", "b"}
234
235 testcases := []struct {
236 str string
237 expected bool
238 }{
239 {
240 str: "a-example",
241 expected: true,
242 },
243 {
244 str: "b-example",
245 expected: true,
246 },
247 {
248 str: "X-example",
249 expected: false,
250 },
251 }
252
253 for _, testCase := range testcases {
254 t.Run(testCase.str, func(t *testing.T) {
Jaewoong Jung3aff5782020-02-11 07:54:35 -0800255 out := HasAnyPrefix(testCase.str, prefixes)
Logan Chien5e877b12018-03-08 18:14:19 +0800256 if out != testCase.expected {
257 t.Errorf("incorrect output:")
258 t.Errorf(" str: %#v", testCase.str)
259 t.Errorf(" prefixes: %#v", prefixes)
260 t.Errorf(" expected: %#v", testCase.expected)
261 t.Errorf(" got: %#v", out)
262 }
263 })
264 }
265}
266
267func TestFilterList(t *testing.T) {
268 input := []string{"a", "b", "c", "c", "b", "d", "a"}
269 filter := []string{"a", "c"}
270 remainder, filtered := FilterList(input, filter)
271
272 expected := []string{"b", "b", "d"}
273 if !reflect.DeepEqual(remainder, expected) {
274 t.Errorf("incorrect remainder output:")
275 t.Errorf(" input: %#v", input)
276 t.Errorf(" filter: %#v", filter)
277 t.Errorf(" expected: %#v", expected)
278 t.Errorf(" got: %#v", remainder)
279 }
280
281 expected = []string{"a", "c", "c", "a"}
282 if !reflect.DeepEqual(filtered, expected) {
283 t.Errorf("incorrect filtered output:")
284 t.Errorf(" input: %#v", input)
285 t.Errorf(" filter: %#v", filter)
286 t.Errorf(" expected: %#v", expected)
287 t.Errorf(" got: %#v", filtered)
288 }
289}
290
291func TestRemoveListFromList(t *testing.T) {
292 input := []string{"a", "b", "c", "d", "a", "c", "d"}
293 filter := []string{"a", "c"}
294 expected := []string{"b", "d", "d"}
295 out := RemoveListFromList(input, filter)
296 if !reflect.DeepEqual(out, expected) {
297 t.Errorf("incorrect output:")
298 t.Errorf(" input: %#v", input)
299 t.Errorf(" filter: %#v", filter)
300 t.Errorf(" expected: %#v", expected)
301 t.Errorf(" got: %#v", out)
302 }
303}
Logan Chien7922ab82018-03-06 18:29:27 +0800304
305func TestRemoveFromList(t *testing.T) {
306 testcases := []struct {
307 name string
308 key string
309 input []string
310 expectedFound bool
311 expectedOut []string
312 }{
313 {
314 name: "remove_one_match",
315 key: "a",
316 input: []string{"a", "b", "c"},
317 expectedFound: true,
318 expectedOut: []string{"b", "c"},
319 },
320 {
321 name: "remove_three_matches",
322 key: "a",
323 input: []string{"a", "b", "a", "c", "a"},
324 expectedFound: true,
325 expectedOut: []string{"b", "c"},
326 },
327 {
328 name: "remove_zero_matches",
329 key: "X",
330 input: []string{"a", "b", "a", "c", "a"},
331 expectedFound: false,
332 expectedOut: []string{"a", "b", "a", "c", "a"},
333 },
334 {
335 name: "remove_all_matches",
336 key: "a",
337 input: []string{"a", "a", "a", "a"},
338 expectedFound: true,
339 expectedOut: []string{},
340 },
341 }
342
343 for _, testCase := range testcases {
344 t.Run(testCase.name, func(t *testing.T) {
345 found, out := RemoveFromList(testCase.key, testCase.input)
346 if found != testCase.expectedFound {
347 t.Errorf("incorrect output:")
348 t.Errorf(" key: %#v", testCase.key)
349 t.Errorf(" input: %#v", testCase.input)
350 t.Errorf(" expected: %#v", testCase.expectedFound)
351 t.Errorf(" got: %#v", found)
352 }
353 if !reflect.DeepEqual(out, testCase.expectedOut) {
354 t.Errorf("incorrect output:")
355 t.Errorf(" key: %#v", testCase.key)
356 t.Errorf(" input: %#v", testCase.input)
357 t.Errorf(" expected: %#v", testCase.expectedOut)
358 t.Errorf(" got: %#v", out)
359 }
360 })
361 }
362}
Colin Cross454c0872019-02-15 23:03:34 -0800363
364func ExampleCopyOf() {
365 a := []string{"1", "2", "3"}
366 b := CopyOf(a)
367 a[0] = "-1"
368 fmt.Printf("a = %q\n", a)
369 fmt.Printf("b = %q\n", b)
370
371 // Output:
372 // a = ["-1" "2" "3"]
373 // b = ["1" "2" "3"]
374}
375
376func ExampleCopyOf_append() {
377 a := make([]string, 1, 2)
378 a[0] = "foo"
379
380 fmt.Println("Without CopyOf:")
381 b := append(a, "bar")
382 c := append(a, "baz")
383 fmt.Printf("a = %q\n", a)
384 fmt.Printf("b = %q\n", b)
385 fmt.Printf("c = %q\n", c)
386
387 a = make([]string, 1, 2)
388 a[0] = "foo"
389
390 fmt.Println("With CopyOf:")
391 b = append(CopyOf(a), "bar")
392 c = append(CopyOf(a), "baz")
393 fmt.Printf("a = %q\n", a)
394 fmt.Printf("b = %q\n", b)
395 fmt.Printf("c = %q\n", c)
396
397 // Output:
398 // Without CopyOf:
399 // a = ["foo"]
400 // b = ["foo" "baz"]
401 // c = ["foo" "baz"]
402 // With CopyOf:
403 // a = ["foo"]
404 // b = ["foo" "bar"]
405 // c = ["foo" "baz"]
406}
Ivan Lozano022a73b2019-09-09 20:29:31 -0700407
408func TestSplitFileExt(t *testing.T) {
409 t.Run("soname with version", func(t *testing.T) {
410 root, suffix, ext := SplitFileExt("libtest.so.1.0.30")
411 expected := "libtest"
412 if root != expected {
413 t.Errorf("root should be %q but got %q", expected, root)
414 }
415 expected = ".so.1.0.30"
416 if suffix != expected {
417 t.Errorf("suffix should be %q but got %q", expected, suffix)
418 }
419 expected = ".so"
420 if ext != expected {
421 t.Errorf("ext should be %q but got %q", expected, ext)
422 }
423 })
424
425 t.Run("soname with svn version", func(t *testing.T) {
426 root, suffix, ext := SplitFileExt("libtest.so.1svn")
427 expected := "libtest"
428 if root != expected {
429 t.Errorf("root should be %q but got %q", expected, root)
430 }
431 expected = ".so.1svn"
432 if suffix != expected {
433 t.Errorf("suffix should be %q but got %q", expected, suffix)
434 }
435 expected = ".so"
436 if ext != expected {
437 t.Errorf("ext should be %q but got %q", expected, ext)
438 }
439 })
440
441 t.Run("version numbers in the middle should be ignored", func(t *testing.T) {
442 root, suffix, ext := SplitFileExt("libtest.1.0.30.so")
443 expected := "libtest.1.0.30"
444 if root != expected {
445 t.Errorf("root should be %q but got %q", expected, root)
446 }
447 expected = ".so"
448 if suffix != expected {
449 t.Errorf("suffix should be %q but got %q", expected, suffix)
450 }
451 expected = ".so"
452 if ext != expected {
453 t.Errorf("ext should be %q but got %q", expected, ext)
454 }
455 })
456
457 t.Run("no known file extension", func(t *testing.T) {
458 root, suffix, ext := SplitFileExt("test.exe")
459 expected := "test"
460 if root != expected {
461 t.Errorf("root should be %q but got %q", expected, root)
462 }
463 expected = ".exe"
464 if suffix != expected {
465 t.Errorf("suffix should be %q but got %q", expected, suffix)
466 }
467 if ext != expected {
468 t.Errorf("ext should be %q but got %q", expected, ext)
469 }
470 })
471}
Colin Cross0a2f7192019-09-23 14:33:09 -0700472
473func Test_Shard(t *testing.T) {
474 type args struct {
475 strings []string
476 shardSize int
477 }
478 tests := []struct {
479 name string
480 args args
481 want [][]string
482 }{
483 {
484 name: "empty",
485 args: args{
486 strings: nil,
487 shardSize: 1,
488 },
489 want: [][]string(nil),
490 },
491 {
492 name: "single shard",
493 args: args{
494 strings: []string{"a", "b"},
495 shardSize: 2,
496 },
497 want: [][]string{{"a", "b"}},
498 },
499 {
500 name: "single short shard",
501 args: args{
502 strings: []string{"a", "b"},
503 shardSize: 3,
504 },
505 want: [][]string{{"a", "b"}},
506 },
507 {
508 name: "shard per input",
509 args: args{
510 strings: []string{"a", "b", "c"},
511 shardSize: 1,
512 },
513 want: [][]string{{"a"}, {"b"}, {"c"}},
514 },
515 {
516 name: "balanced shards",
517 args: args{
518 strings: []string{"a", "b", "c", "d"},
519 shardSize: 2,
520 },
521 want: [][]string{{"a", "b"}, {"c", "d"}},
522 },
523 {
524 name: "unbalanced shards",
525 args: args{
526 strings: []string{"a", "b", "c"},
527 shardSize: 2,
528 },
529 want: [][]string{{"a", "b"}, {"c"}},
530 },
531 }
532 for _, tt := range tests {
533 t.Run(tt.name, func(t *testing.T) {
534 t.Run("strings", func(t *testing.T) {
535 if got := ShardStrings(tt.args.strings, tt.args.shardSize); !reflect.DeepEqual(got, tt.want) {
536 t.Errorf("ShardStrings(%v, %v) = %v, want %v",
537 tt.args.strings, tt.args.shardSize, got, tt.want)
538 }
539 })
540
541 t.Run("paths", func(t *testing.T) {
542 stringsToPaths := func(strings []string) Paths {
543 if strings == nil {
544 return nil
545 }
546 paths := make(Paths, len(strings))
547 for i, s := range strings {
548 paths[i] = PathForTesting(s)
549 }
550 return paths
551 }
552
553 paths := stringsToPaths(tt.args.strings)
554
555 var want []Paths
556 if sWant := tt.want; sWant != nil {
557 want = make([]Paths, len(sWant))
558 for i, w := range sWant {
559 want[i] = stringsToPaths(w)
560 }
561 }
562
563 if got := ShardPaths(paths, tt.args.shardSize); !reflect.DeepEqual(got, want) {
564 t.Errorf("ShardPaths(%v, %v) = %v, want %v",
565 paths, tt.args.shardSize, got, want)
566 }
567 })
568 })
569 }
570}