• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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 (
18	"fmt"
19	"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}
122
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) {
255			out := HasAnyPrefix(testCase.str, prefixes)
256			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}
304
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}
363
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}
407
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}
472
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}
571