123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- // Copyright 2017 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package android
- import (
- "fmt"
- "reflect"
- "strconv"
- "strings"
- "testing"
- )
- var firstUniqueStringsTestCases = []struct {
- in []string
- out []string
- }{
- {
- in: []string{"a"},
- out: []string{"a"},
- },
- {
- in: []string{"a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"a", "a"},
- out: []string{"a"},
- },
- {
- in: []string{"a", "b", "a"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"b", "a", "a"},
- out: []string{"b", "a"},
- },
- {
- in: []string{"a", "a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"a", "b", "a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
- out: []string{"liblog", "libdl", "libc++", "libc", "libm"},
- },
- }
- func TestFirstUniqueStrings(t *testing.T) {
- f := func(t *testing.T, imp func([]string) []string, in, want []string) {
- t.Helper()
- out := imp(in)
- if !reflect.DeepEqual(out, want) {
- t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", in)
- t.Errorf(" expected: %#v", want)
- t.Errorf(" got: %#v", out)
- }
- }
- for _, testCase := range firstUniqueStringsTestCases {
- t.Run("list", func(t *testing.T) {
- f(t, firstUniqueList[string], testCase.in, testCase.out)
- })
- t.Run("map", func(t *testing.T) {
- f(t, firstUniqueMap[string], testCase.in, testCase.out)
- })
- }
- }
- var lastUniqueStringsTestCases = []struct {
- in []string
- out []string
- }{
- {
- in: []string{"a"},
- out: []string{"a"},
- },
- {
- in: []string{"a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"a", "a"},
- out: []string{"a"},
- },
- {
- in: []string{"a", "b", "a"},
- out: []string{"b", "a"},
- },
- {
- in: []string{"b", "a", "a"},
- out: []string{"b", "a"},
- },
- {
- in: []string{"a", "a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"a", "b", "a", "b"},
- out: []string{"a", "b"},
- },
- {
- in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
- out: []string{"liblog", "libc++", "libdl", "libc", "libm"},
- },
- }
- func TestLastUniqueStrings(t *testing.T) {
- for _, testCase := range lastUniqueStringsTestCases {
- out := LastUniqueStrings(testCase.in)
- if !reflect.DeepEqual(out, testCase.out) {
- t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", testCase.in)
- t.Errorf(" expected: %#v", testCase.out)
- t.Errorf(" got: %#v", out)
- }
- }
- }
- func TestJoinWithPrefix(t *testing.T) {
- testcases := []struct {
- name string
- input []string
- expected string
- }{
- {
- name: "zero_inputs",
- input: []string{},
- expected: "",
- },
- {
- name: "one_input",
- input: []string{"a"},
- expected: "prefix:a",
- },
- {
- name: "two_inputs",
- input: []string{"a", "b"},
- expected: "prefix:a prefix:b",
- },
- }
- prefix := "prefix:"
- for _, testCase := range testcases {
- t.Run(testCase.name, func(t *testing.T) {
- out := JoinWithPrefix(testCase.input, prefix)
- if out != testCase.expected {
- t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", testCase.input)
- t.Errorf(" prefix: %#v", prefix)
- t.Errorf(" expected: %#v", testCase.expected)
- t.Errorf(" got: %#v", out)
- }
- })
- }
- }
- func TestIndexList(t *testing.T) {
- input := []string{"a", "b", "c"}
- testcases := []struct {
- key string
- expected int
- }{
- {
- key: "a",
- expected: 0,
- },
- {
- key: "b",
- expected: 1,
- },
- {
- key: "c",
- expected: 2,
- },
- {
- key: "X",
- expected: -1,
- },
- }
- for _, testCase := range testcases {
- t.Run(testCase.key, func(t *testing.T) {
- out := IndexList(testCase.key, input)
- if out != testCase.expected {
- t.Errorf("incorrect output:")
- t.Errorf(" key: %#v", testCase.key)
- t.Errorf(" input: %#v", input)
- t.Errorf(" expected: %#v", testCase.expected)
- t.Errorf(" got: %#v", out)
- }
- })
- }
- }
- func TestInList(t *testing.T) {
- input := []string{"a"}
- testcases := []struct {
- key string
- expected bool
- }{
- {
- key: "a",
- expected: true,
- },
- {
- key: "X",
- expected: false,
- },
- }
- for _, testCase := range testcases {
- t.Run(testCase.key, func(t *testing.T) {
- out := InList(testCase.key, input)
- if out != testCase.expected {
- t.Errorf("incorrect output:")
- t.Errorf(" key: %#v", testCase.key)
- t.Errorf(" input: %#v", input)
- t.Errorf(" expected: %#v", testCase.expected)
- t.Errorf(" got: %#v", out)
- }
- })
- }
- }
- func TestPrefixInList(t *testing.T) {
- prefixes := []string{"a", "b"}
- testcases := []struct {
- str string
- expected bool
- }{
- {
- str: "a-example",
- expected: true,
- },
- {
- str: "b-example",
- expected: true,
- },
- {
- str: "X-example",
- expected: false,
- },
- }
- for _, testCase := range testcases {
- t.Run(testCase.str, func(t *testing.T) {
- out := HasAnyPrefix(testCase.str, prefixes)
- if out != testCase.expected {
- t.Errorf("incorrect output:")
- t.Errorf(" str: %#v", testCase.str)
- t.Errorf(" prefixes: %#v", prefixes)
- t.Errorf(" expected: %#v", testCase.expected)
- t.Errorf(" got: %#v", out)
- }
- })
- }
- }
- func TestFilterList(t *testing.T) {
- input := []string{"a", "b", "c", "c", "b", "d", "a"}
- filter := []string{"a", "c"}
- remainder, filtered := FilterList(input, filter)
- expected := []string{"b", "b", "d"}
- if !reflect.DeepEqual(remainder, expected) {
- t.Errorf("incorrect remainder output:")
- t.Errorf(" input: %#v", input)
- t.Errorf(" filter: %#v", filter)
- t.Errorf(" expected: %#v", expected)
- t.Errorf(" got: %#v", remainder)
- }
- expected = []string{"a", "c", "c", "a"}
- if !reflect.DeepEqual(filtered, expected) {
- t.Errorf("incorrect filtered output:")
- t.Errorf(" input: %#v", input)
- t.Errorf(" filter: %#v", filter)
- t.Errorf(" expected: %#v", expected)
- t.Errorf(" got: %#v", filtered)
- }
- }
- func TestFilterListPred(t *testing.T) {
- pred := func(s string) bool { return strings.HasPrefix(s, "a/") }
- AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "b/a", "a/b"}, pred), []string{"a/c", "a/b"})
- AssertArrayString(t, "filter", FilterListPred([]string{"b/c", "a/a", "b/b"}, pred), []string{"a/a"})
- AssertArrayString(t, "filter", FilterListPred([]string{"c/c", "b/a", "c/b"}, pred), []string{})
- AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "a/a", "a/b"}, pred), []string{"a/c", "a/a", "a/b"})
- }
- func TestRemoveListFromList(t *testing.T) {
- input := []string{"a", "b", "c", "d", "a", "c", "d"}
- filter := []string{"a", "c"}
- expected := []string{"b", "d", "d"}
- out := RemoveListFromList(input, filter)
- if !reflect.DeepEqual(out, expected) {
- t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", input)
- t.Errorf(" filter: %#v", filter)
- t.Errorf(" expected: %#v", expected)
- t.Errorf(" got: %#v", out)
- }
- }
- func TestRemoveFromList(t *testing.T) {
- testcases := []struct {
- name string
- key string
- input []string
- expectedFound bool
- expectedOut []string
- }{
- {
- name: "remove_one_match",
- key: "a",
- input: []string{"a", "b", "c"},
- expectedFound: true,
- expectedOut: []string{"b", "c"},
- },
- {
- name: "remove_three_matches",
- key: "a",
- input: []string{"a", "b", "a", "c", "a"},
- expectedFound: true,
- expectedOut: []string{"b", "c"},
- },
- {
- name: "remove_zero_matches",
- key: "X",
- input: []string{"a", "b", "a", "c", "a"},
- expectedFound: false,
- expectedOut: []string{"a", "b", "a", "c", "a"},
- },
- {
- name: "remove_all_matches",
- key: "a",
- input: []string{"a", "a", "a", "a"},
- expectedFound: true,
- expectedOut: []string{},
- },
- }
- for _, testCase := range testcases {
- t.Run(testCase.name, func(t *testing.T) {
- found, out := RemoveFromList(testCase.key, testCase.input)
- if found != testCase.expectedFound {
- t.Errorf("incorrect output:")
- t.Errorf(" key: %#v", testCase.key)
- t.Errorf(" input: %#v", testCase.input)
- t.Errorf(" expected: %#v", testCase.expectedFound)
- t.Errorf(" got: %#v", found)
- }
- if !reflect.DeepEqual(out, testCase.expectedOut) {
- t.Errorf("incorrect output:")
- t.Errorf(" key: %#v", testCase.key)
- t.Errorf(" input: %#v", testCase.input)
- t.Errorf(" expected: %#v", testCase.expectedOut)
- t.Errorf(" got: %#v", out)
- }
- })
- }
- }
- func TestCopyOfEmptyAndNil(t *testing.T) {
- emptyList := []string{}
- copyOfEmptyList := CopyOf(emptyList)
- AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
- copyOfNilList := CopyOf([]string(nil))
- AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
- }
- func ExampleCopyOf() {
- a := []string{"1", "2", "3"}
- b := CopyOf(a)
- a[0] = "-1"
- fmt.Printf("a = %q\n", a)
- fmt.Printf("b = %q\n", b)
- // Output:
- // a = ["-1" "2" "3"]
- // b = ["1" "2" "3"]
- }
- func ExampleCopyOf_append() {
- a := make([]string, 1, 2)
- a[0] = "foo"
- fmt.Println("Without CopyOf:")
- b := append(a, "bar")
- c := append(a, "baz")
- fmt.Printf("a = %q\n", a)
- fmt.Printf("b = %q\n", b)
- fmt.Printf("c = %q\n", c)
- a = make([]string, 1, 2)
- a[0] = "foo"
- fmt.Println("With CopyOf:")
- b = append(CopyOf(a), "bar")
- c = append(CopyOf(a), "baz")
- fmt.Printf("a = %q\n", a)
- fmt.Printf("b = %q\n", b)
- fmt.Printf("c = %q\n", c)
- // Output:
- // Without CopyOf:
- // a = ["foo"]
- // b = ["foo" "baz"]
- // c = ["foo" "baz"]
- // With CopyOf:
- // a = ["foo"]
- // b = ["foo" "bar"]
- // c = ["foo" "baz"]
- }
- func TestSplitFileExt(t *testing.T) {
- t.Run("soname with version", func(t *testing.T) {
- root, suffix, ext := SplitFileExt("libtest.so.1.0.30")
- expected := "libtest"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so.1.0.30"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
- t.Run("soname with svn version", func(t *testing.T) {
- root, suffix, ext := SplitFileExt("libtest.so.1svn")
- expected := "libtest"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so.1svn"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
- t.Run("version numbers in the middle should be ignored", func(t *testing.T) {
- root, suffix, ext := SplitFileExt("libtest.1.0.30.so")
- expected := "libtest.1.0.30"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
- t.Run("no known file extension", func(t *testing.T) {
- root, suffix, ext := SplitFileExt("test.exe")
- expected := "test"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".exe"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
- }
- func Test_Shard(t *testing.T) {
- type args struct {
- strings []string
- shardSize int
- }
- tests := []struct {
- name string
- args args
- want [][]string
- }{
- {
- name: "empty",
- args: args{
- strings: nil,
- shardSize: 1,
- },
- want: [][]string(nil),
- },
- {
- name: "single shard",
- args: args{
- strings: []string{"a", "b"},
- shardSize: 2,
- },
- want: [][]string{{"a", "b"}},
- },
- {
- name: "single short shard",
- args: args{
- strings: []string{"a", "b"},
- shardSize: 3,
- },
- want: [][]string{{"a", "b"}},
- },
- {
- name: "shard per input",
- args: args{
- strings: []string{"a", "b", "c"},
- shardSize: 1,
- },
- want: [][]string{{"a"}, {"b"}, {"c"}},
- },
- {
- name: "balanced shards",
- args: args{
- strings: []string{"a", "b", "c", "d"},
- shardSize: 2,
- },
- want: [][]string{{"a", "b"}, {"c", "d"}},
- },
- {
- name: "unbalanced shards",
- args: args{
- strings: []string{"a", "b", "c"},
- shardSize: 2,
- },
- want: [][]string{{"a", "b"}, {"c"}},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- t.Run("strings", func(t *testing.T) {
- if got := ShardStrings(tt.args.strings, tt.args.shardSize); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("ShardStrings(%v, %v) = %v, want %v",
- tt.args.strings, tt.args.shardSize, got, tt.want)
- }
- })
- t.Run("paths", func(t *testing.T) {
- stringsToPaths := func(strings []string) Paths {
- if strings == nil {
- return nil
- }
- paths := make(Paths, len(strings))
- for i, s := range strings {
- paths[i] = PathForTesting(s)
- }
- return paths
- }
- paths := stringsToPaths(tt.args.strings)
- var want []Paths
- if sWant := tt.want; sWant != nil {
- want = make([]Paths, len(sWant))
- for i, w := range sWant {
- want[i] = stringsToPaths(w)
- }
- }
- if got := ShardPaths(paths, tt.args.shardSize); !reflect.DeepEqual(got, want) {
- t.Errorf("ShardPaths(%v, %v) = %v, want %v",
- paths, tt.args.shardSize, got, want)
- }
- })
- })
- }
- }
- func BenchmarkFirstUniqueStrings(b *testing.B) {
- implementations := []struct {
- name string
- f func([]string) []string
- }{
- {
- name: "list",
- f: firstUniqueList[string],
- },
- {
- name: "map",
- f: firstUniqueMap[string],
- },
- {
- name: "optimal",
- f: FirstUniqueStrings,
- },
- }
- const maxSize = 1024
- uniqueStrings := make([]string, maxSize)
- for i := range uniqueStrings {
- uniqueStrings[i] = strconv.Itoa(i)
- }
- sameString := make([]string, maxSize)
- for i := range sameString {
- sameString[i] = uniqueStrings[0]
- }
- f := func(b *testing.B, imp func([]string) []string, s []string) {
- for i := 0; i < b.N; i++ {
- b.ReportAllocs()
- s = append([]string(nil), s...)
- imp(s)
- }
- }
- for n := 1; n <= maxSize; n <<= 1 {
- b.Run(strconv.Itoa(n), func(b *testing.B) {
- for _, implementation := range implementations {
- b.Run(implementation.name, func(b *testing.B) {
- b.Run("same", func(b *testing.B) {
- f(b, implementation.f, sameString[:n])
- })
- b.Run("unique", func(b *testing.B) {
- f(b, implementation.f, uniqueStrings[:n])
- })
- })
- }
- })
- }
- }
- func testSortedKeysHelper[K Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
- t.Helper()
- t.Run(name, func(t *testing.T) {
- actual := SortedKeys(input)
- if !reflect.DeepEqual(actual, expected) {
- t.Errorf("expected %v, got %v", expected, actual)
- }
- })
- }
- func TestSortedKeys(t *testing.T) {
- testSortedKeysHelper(t, "simple", map[string]string{
- "b": "bar",
- "a": "foo",
- }, []string{
- "a",
- "b",
- })
- testSortedKeysHelper(t, "ints", map[int]interface{}{
- 10: nil,
- 5: nil,
- }, []int{
- 5,
- 10,
- })
- testSortedKeysHelper(t, "nil", map[string]string(nil), nil)
- testSortedKeysHelper(t, "empty", map[string]string{}, nil)
- }
- func TestSortedStringValues(t *testing.T) {
- testCases := []struct {
- name string
- in interface{}
- expected []string
- }{
- {
- name: "nil",
- in: map[string]string(nil),
- expected: nil,
- },
- {
- name: "empty",
- in: map[string]string{},
- expected: nil,
- },
- {
- name: "simple",
- in: map[string]string{"foo": "a", "bar": "b"},
- expected: []string{"a", "b"},
- },
- {
- name: "duplicates",
- in: map[string]string{"foo": "a", "bar": "b", "baz": "b"},
- expected: []string{"a", "b", "b"},
- },
- }
- for _, tt := range testCases {
- t.Run(tt.name, func(t *testing.T) {
- got := SortedStringValues(tt.in)
- if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
- t.Errorf("wanted %q, got %q", w, g)
- }
- })
- }
- }
- func TestSortedUniqueStringValues(t *testing.T) {
- testCases := []struct {
- name string
- in interface{}
- expected []string
- }{
- {
- name: "nil",
- in: map[string]string(nil),
- expected: nil,
- },
- {
- name: "empty",
- in: map[string]string{},
- expected: nil,
- },
- {
- name: "simple",
- in: map[string]string{"foo": "a", "bar": "b"},
- expected: []string{"a", "b"},
- },
- {
- name: "duplicates",
- in: map[string]string{"foo": "a", "bar": "b", "baz": "b"},
- expected: []string{"a", "b"},
- },
- }
- for _, tt := range testCases {
- t.Run(tt.name, func(t *testing.T) {
- got := SortedUniqueStringValues(tt.in)
- if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
- t.Errorf("wanted %q, got %q", w, g)
- }
- })
- }
- }
|