util_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  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. package android
  15. import (
  16. "fmt"
  17. "reflect"
  18. "strconv"
  19. "strings"
  20. "testing"
  21. )
  22. var firstUniqueStringsTestCases = []struct {
  23. in []string
  24. out []string
  25. }{
  26. {
  27. in: []string{"a"},
  28. out: []string{"a"},
  29. },
  30. {
  31. in: []string{"a", "b"},
  32. out: []string{"a", "b"},
  33. },
  34. {
  35. in: []string{"a", "a"},
  36. out: []string{"a"},
  37. },
  38. {
  39. in: []string{"a", "b", "a"},
  40. out: []string{"a", "b"},
  41. },
  42. {
  43. in: []string{"b", "a", "a"},
  44. out: []string{"b", "a"},
  45. },
  46. {
  47. in: []string{"a", "a", "b"},
  48. out: []string{"a", "b"},
  49. },
  50. {
  51. in: []string{"a", "b", "a", "b"},
  52. out: []string{"a", "b"},
  53. },
  54. {
  55. in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
  56. out: []string{"liblog", "libdl", "libc++", "libc", "libm"},
  57. },
  58. }
  59. func TestFirstUniqueStrings(t *testing.T) {
  60. f := func(t *testing.T, imp func([]string) []string, in, want []string) {
  61. t.Helper()
  62. out := imp(in)
  63. if !reflect.DeepEqual(out, want) {
  64. t.Errorf("incorrect output:")
  65. t.Errorf(" input: %#v", in)
  66. t.Errorf(" expected: %#v", want)
  67. t.Errorf(" got: %#v", out)
  68. }
  69. }
  70. for _, testCase := range firstUniqueStringsTestCases {
  71. t.Run("list", func(t *testing.T) {
  72. f(t, firstUniqueList[string], testCase.in, testCase.out)
  73. })
  74. t.Run("map", func(t *testing.T) {
  75. f(t, firstUniqueMap[string], testCase.in, testCase.out)
  76. })
  77. }
  78. }
  79. var lastUniqueStringsTestCases = []struct {
  80. in []string
  81. out []string
  82. }{
  83. {
  84. in: []string{"a"},
  85. out: []string{"a"},
  86. },
  87. {
  88. in: []string{"a", "b"},
  89. out: []string{"a", "b"},
  90. },
  91. {
  92. in: []string{"a", "a"},
  93. out: []string{"a"},
  94. },
  95. {
  96. in: []string{"a", "b", "a"},
  97. out: []string{"b", "a"},
  98. },
  99. {
  100. in: []string{"b", "a", "a"},
  101. out: []string{"b", "a"},
  102. },
  103. {
  104. in: []string{"a", "a", "b"},
  105. out: []string{"a", "b"},
  106. },
  107. {
  108. in: []string{"a", "b", "a", "b"},
  109. out: []string{"a", "b"},
  110. },
  111. {
  112. in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"},
  113. out: []string{"liblog", "libc++", "libdl", "libc", "libm"},
  114. },
  115. }
  116. func TestLastUniqueStrings(t *testing.T) {
  117. for _, testCase := range lastUniqueStringsTestCases {
  118. out := LastUniqueStrings(testCase.in)
  119. if !reflect.DeepEqual(out, testCase.out) {
  120. t.Errorf("incorrect output:")
  121. t.Errorf(" input: %#v", testCase.in)
  122. t.Errorf(" expected: %#v", testCase.out)
  123. t.Errorf(" got: %#v", out)
  124. }
  125. }
  126. }
  127. func TestJoinWithPrefix(t *testing.T) {
  128. testcases := []struct {
  129. name string
  130. input []string
  131. expected string
  132. }{
  133. {
  134. name: "zero_inputs",
  135. input: []string{},
  136. expected: "",
  137. },
  138. {
  139. name: "one_input",
  140. input: []string{"a"},
  141. expected: "prefix:a",
  142. },
  143. {
  144. name: "two_inputs",
  145. input: []string{"a", "b"},
  146. expected: "prefix:a prefix:b",
  147. },
  148. }
  149. prefix := "prefix:"
  150. for _, testCase := range testcases {
  151. t.Run(testCase.name, func(t *testing.T) {
  152. out := JoinWithPrefix(testCase.input, prefix)
  153. if out != testCase.expected {
  154. t.Errorf("incorrect output:")
  155. t.Errorf(" input: %#v", testCase.input)
  156. t.Errorf(" prefix: %#v", prefix)
  157. t.Errorf(" expected: %#v", testCase.expected)
  158. t.Errorf(" got: %#v", out)
  159. }
  160. })
  161. }
  162. }
  163. func TestIndexList(t *testing.T) {
  164. input := []string{"a", "b", "c"}
  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. for _, testCase := range testcases {
  187. t.Run(testCase.key, func(t *testing.T) {
  188. out := IndexList(testCase.key, input)
  189. if out != testCase.expected {
  190. t.Errorf("incorrect output:")
  191. t.Errorf(" key: %#v", testCase.key)
  192. t.Errorf(" input: %#v", input)
  193. t.Errorf(" expected: %#v", testCase.expected)
  194. t.Errorf(" got: %#v", out)
  195. }
  196. })
  197. }
  198. }
  199. func TestInList(t *testing.T) {
  200. input := []string{"a"}
  201. testcases := []struct {
  202. key string
  203. expected bool
  204. }{
  205. {
  206. key: "a",
  207. expected: true,
  208. },
  209. {
  210. key: "X",
  211. expected: false,
  212. },
  213. }
  214. for _, testCase := range testcases {
  215. t.Run(testCase.key, func(t *testing.T) {
  216. out := InList(testCase.key, input)
  217. if out != testCase.expected {
  218. t.Errorf("incorrect output:")
  219. t.Errorf(" key: %#v", testCase.key)
  220. t.Errorf(" input: %#v", input)
  221. t.Errorf(" expected: %#v", testCase.expected)
  222. t.Errorf(" got: %#v", out)
  223. }
  224. })
  225. }
  226. }
  227. func TestPrefixInList(t *testing.T) {
  228. prefixes := []string{"a", "b"}
  229. testcases := []struct {
  230. str string
  231. expected bool
  232. }{
  233. {
  234. str: "a-example",
  235. expected: true,
  236. },
  237. {
  238. str: "b-example",
  239. expected: true,
  240. },
  241. {
  242. str: "X-example",
  243. expected: false,
  244. },
  245. }
  246. for _, testCase := range testcases {
  247. t.Run(testCase.str, func(t *testing.T) {
  248. out := HasAnyPrefix(testCase.str, prefixes)
  249. if out != testCase.expected {
  250. t.Errorf("incorrect output:")
  251. t.Errorf(" str: %#v", testCase.str)
  252. t.Errorf(" prefixes: %#v", prefixes)
  253. t.Errorf(" expected: %#v", testCase.expected)
  254. t.Errorf(" got: %#v", out)
  255. }
  256. })
  257. }
  258. }
  259. func TestFilterList(t *testing.T) {
  260. input := []string{"a", "b", "c", "c", "b", "d", "a"}
  261. filter := []string{"a", "c"}
  262. remainder, filtered := FilterList(input, filter)
  263. expected := []string{"b", "b", "d"}
  264. if !reflect.DeepEqual(remainder, expected) {
  265. t.Errorf("incorrect remainder output:")
  266. t.Errorf(" input: %#v", input)
  267. t.Errorf(" filter: %#v", filter)
  268. t.Errorf(" expected: %#v", expected)
  269. t.Errorf(" got: %#v", remainder)
  270. }
  271. expected = []string{"a", "c", "c", "a"}
  272. if !reflect.DeepEqual(filtered, expected) {
  273. t.Errorf("incorrect filtered output:")
  274. t.Errorf(" input: %#v", input)
  275. t.Errorf(" filter: %#v", filter)
  276. t.Errorf(" expected: %#v", expected)
  277. t.Errorf(" got: %#v", filtered)
  278. }
  279. }
  280. func TestFilterListPred(t *testing.T) {
  281. pred := func(s string) bool { return strings.HasPrefix(s, "a/") }
  282. AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "b/a", "a/b"}, pred), []string{"a/c", "a/b"})
  283. AssertArrayString(t, "filter", FilterListPred([]string{"b/c", "a/a", "b/b"}, pred), []string{"a/a"})
  284. AssertArrayString(t, "filter", FilterListPred([]string{"c/c", "b/a", "c/b"}, pred), []string{})
  285. AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "a/a", "a/b"}, pred), []string{"a/c", "a/a", "a/b"})
  286. }
  287. func TestRemoveListFromList(t *testing.T) {
  288. input := []string{"a", "b", "c", "d", "a", "c", "d"}
  289. filter := []string{"a", "c"}
  290. expected := []string{"b", "d", "d"}
  291. out := RemoveListFromList(input, filter)
  292. if !reflect.DeepEqual(out, expected) {
  293. t.Errorf("incorrect output:")
  294. t.Errorf(" input: %#v", input)
  295. t.Errorf(" filter: %#v", filter)
  296. t.Errorf(" expected: %#v", expected)
  297. t.Errorf(" got: %#v", out)
  298. }
  299. }
  300. func TestRemoveFromList(t *testing.T) {
  301. testcases := []struct {
  302. name string
  303. key string
  304. input []string
  305. expectedFound bool
  306. expectedOut []string
  307. }{
  308. {
  309. name: "remove_one_match",
  310. key: "a",
  311. input: []string{"a", "b", "c"},
  312. expectedFound: true,
  313. expectedOut: []string{"b", "c"},
  314. },
  315. {
  316. name: "remove_three_matches",
  317. key: "a",
  318. input: []string{"a", "b", "a", "c", "a"},
  319. expectedFound: true,
  320. expectedOut: []string{"b", "c"},
  321. },
  322. {
  323. name: "remove_zero_matches",
  324. key: "X",
  325. input: []string{"a", "b", "a", "c", "a"},
  326. expectedFound: false,
  327. expectedOut: []string{"a", "b", "a", "c", "a"},
  328. },
  329. {
  330. name: "remove_all_matches",
  331. key: "a",
  332. input: []string{"a", "a", "a", "a"},
  333. expectedFound: true,
  334. expectedOut: []string{},
  335. },
  336. }
  337. for _, testCase := range testcases {
  338. t.Run(testCase.name, func(t *testing.T) {
  339. found, out := RemoveFromList(testCase.key, testCase.input)
  340. if found != testCase.expectedFound {
  341. t.Errorf("incorrect output:")
  342. t.Errorf(" key: %#v", testCase.key)
  343. t.Errorf(" input: %#v", testCase.input)
  344. t.Errorf(" expected: %#v", testCase.expectedFound)
  345. t.Errorf(" got: %#v", found)
  346. }
  347. if !reflect.DeepEqual(out, testCase.expectedOut) {
  348. t.Errorf("incorrect output:")
  349. t.Errorf(" key: %#v", testCase.key)
  350. t.Errorf(" input: %#v", testCase.input)
  351. t.Errorf(" expected: %#v", testCase.expectedOut)
  352. t.Errorf(" got: %#v", out)
  353. }
  354. })
  355. }
  356. }
  357. func TestCopyOfEmptyAndNil(t *testing.T) {
  358. emptyList := []string{}
  359. copyOfEmptyList := CopyOf(emptyList)
  360. AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
  361. copyOfNilList := CopyOf([]string(nil))
  362. AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
  363. }
  364. func 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. // Output:
  371. // a = ["-1" "2" "3"]
  372. // b = ["1" "2" "3"]
  373. }
  374. func ExampleCopyOf_append() {
  375. a := make([]string, 1, 2)
  376. a[0] = "foo"
  377. fmt.Println("Without CopyOf:")
  378. b := append(a, "bar")
  379. c := append(a, "baz")
  380. fmt.Printf("a = %q\n", a)
  381. fmt.Printf("b = %q\n", b)
  382. fmt.Printf("c = %q\n", c)
  383. a = make([]string, 1, 2)
  384. a[0] = "foo"
  385. fmt.Println("With CopyOf:")
  386. b = append(CopyOf(a), "bar")
  387. c = append(CopyOf(a), "baz")
  388. fmt.Printf("a = %q\n", a)
  389. fmt.Printf("b = %q\n", b)
  390. fmt.Printf("c = %q\n", c)
  391. // Output:
  392. // Without CopyOf:
  393. // a = ["foo"]
  394. // b = ["foo" "baz"]
  395. // c = ["foo" "baz"]
  396. // With CopyOf:
  397. // a = ["foo"]
  398. // b = ["foo" "bar"]
  399. // c = ["foo" "baz"]
  400. }
  401. func TestSplitFileExt(t *testing.T) {
  402. t.Run("soname with version", func(t *testing.T) {
  403. root, suffix, ext := SplitFileExt("libtest.so.1.0.30")
  404. expected := "libtest"
  405. if root != expected {
  406. t.Errorf("root should be %q but got %q", expected, root)
  407. }
  408. expected = ".so.1.0.30"
  409. if suffix != expected {
  410. t.Errorf("suffix should be %q but got %q", expected, suffix)
  411. }
  412. expected = ".so"
  413. if ext != expected {
  414. t.Errorf("ext should be %q but got %q", expected, ext)
  415. }
  416. })
  417. t.Run("soname with svn version", func(t *testing.T) {
  418. root, suffix, ext := SplitFileExt("libtest.so.1svn")
  419. expected := "libtest"
  420. if root != expected {
  421. t.Errorf("root should be %q but got %q", expected, root)
  422. }
  423. expected = ".so.1svn"
  424. if suffix != expected {
  425. t.Errorf("suffix should be %q but got %q", expected, suffix)
  426. }
  427. expected = ".so"
  428. if ext != expected {
  429. t.Errorf("ext should be %q but got %q", expected, ext)
  430. }
  431. })
  432. t.Run("version numbers in the middle should be ignored", func(t *testing.T) {
  433. root, suffix, ext := SplitFileExt("libtest.1.0.30.so")
  434. expected := "libtest.1.0.30"
  435. if root != expected {
  436. t.Errorf("root should be %q but got %q", expected, root)
  437. }
  438. expected = ".so"
  439. if suffix != expected {
  440. t.Errorf("suffix should be %q but got %q", expected, suffix)
  441. }
  442. expected = ".so"
  443. if ext != expected {
  444. t.Errorf("ext should be %q but got %q", expected, ext)
  445. }
  446. })
  447. t.Run("no known file extension", func(t *testing.T) {
  448. root, suffix, ext := SplitFileExt("test.exe")
  449. expected := "test"
  450. if root != expected {
  451. t.Errorf("root should be %q but got %q", expected, root)
  452. }
  453. expected = ".exe"
  454. if suffix != expected {
  455. t.Errorf("suffix should be %q but got %q", expected, suffix)
  456. }
  457. if ext != expected {
  458. t.Errorf("ext should be %q but got %q", expected, ext)
  459. }
  460. })
  461. }
  462. func Test_Shard(t *testing.T) {
  463. type args struct {
  464. strings []string
  465. shardSize int
  466. }
  467. tests := []struct {
  468. name string
  469. args args
  470. want [][]string
  471. }{
  472. {
  473. name: "empty",
  474. args: args{
  475. strings: nil,
  476. shardSize: 1,
  477. },
  478. want: [][]string(nil),
  479. },
  480. {
  481. name: "single shard",
  482. args: args{
  483. strings: []string{"a", "b"},
  484. shardSize: 2,
  485. },
  486. want: [][]string{{"a", "b"}},
  487. },
  488. {
  489. name: "single short shard",
  490. args: args{
  491. strings: []string{"a", "b"},
  492. shardSize: 3,
  493. },
  494. want: [][]string{{"a", "b"}},
  495. },
  496. {
  497. name: "shard per input",
  498. args: args{
  499. strings: []string{"a", "b", "c"},
  500. shardSize: 1,
  501. },
  502. want: [][]string{{"a"}, {"b"}, {"c"}},
  503. },
  504. {
  505. name: "balanced shards",
  506. args: args{
  507. strings: []string{"a", "b", "c", "d"},
  508. shardSize: 2,
  509. },
  510. want: [][]string{{"a", "b"}, {"c", "d"}},
  511. },
  512. {
  513. name: "unbalanced shards",
  514. args: args{
  515. strings: []string{"a", "b", "c"},
  516. shardSize: 2,
  517. },
  518. want: [][]string{{"a", "b"}, {"c"}},
  519. },
  520. }
  521. for _, tt := range tests {
  522. t.Run(tt.name, func(t *testing.T) {
  523. t.Run("strings", func(t *testing.T) {
  524. if got := ShardStrings(tt.args.strings, tt.args.shardSize); !reflect.DeepEqual(got, tt.want) {
  525. t.Errorf("ShardStrings(%v, %v) = %v, want %v",
  526. tt.args.strings, tt.args.shardSize, got, tt.want)
  527. }
  528. })
  529. t.Run("paths", func(t *testing.T) {
  530. stringsToPaths := func(strings []string) Paths {
  531. if strings == nil {
  532. return nil
  533. }
  534. paths := make(Paths, len(strings))
  535. for i, s := range strings {
  536. paths[i] = PathForTesting(s)
  537. }
  538. return paths
  539. }
  540. paths := stringsToPaths(tt.args.strings)
  541. var want []Paths
  542. if sWant := tt.want; sWant != nil {
  543. want = make([]Paths, len(sWant))
  544. for i, w := range sWant {
  545. want[i] = stringsToPaths(w)
  546. }
  547. }
  548. if got := ShardPaths(paths, tt.args.shardSize); !reflect.DeepEqual(got, want) {
  549. t.Errorf("ShardPaths(%v, %v) = %v, want %v",
  550. paths, tt.args.shardSize, got, want)
  551. }
  552. })
  553. })
  554. }
  555. }
  556. func BenchmarkFirstUniqueStrings(b *testing.B) {
  557. implementations := []struct {
  558. name string
  559. f func([]string) []string
  560. }{
  561. {
  562. name: "list",
  563. f: firstUniqueList[string],
  564. },
  565. {
  566. name: "map",
  567. f: firstUniqueMap[string],
  568. },
  569. {
  570. name: "optimal",
  571. f: FirstUniqueStrings,
  572. },
  573. }
  574. const maxSize = 1024
  575. uniqueStrings := make([]string, maxSize)
  576. for i := range uniqueStrings {
  577. uniqueStrings[i] = strconv.Itoa(i)
  578. }
  579. sameString := make([]string, maxSize)
  580. for i := range sameString {
  581. sameString[i] = uniqueStrings[0]
  582. }
  583. f := func(b *testing.B, imp func([]string) []string, s []string) {
  584. for i := 0; i < b.N; i++ {
  585. b.ReportAllocs()
  586. s = append([]string(nil), s...)
  587. imp(s)
  588. }
  589. }
  590. for n := 1; n <= maxSize; n <<= 1 {
  591. b.Run(strconv.Itoa(n), func(b *testing.B) {
  592. for _, implementation := range implementations {
  593. b.Run(implementation.name, func(b *testing.B) {
  594. b.Run("same", func(b *testing.B) {
  595. f(b, implementation.f, sameString[:n])
  596. })
  597. b.Run("unique", func(b *testing.B) {
  598. f(b, implementation.f, uniqueStrings[:n])
  599. })
  600. })
  601. }
  602. })
  603. }
  604. }
  605. func testSortedKeysHelper[K Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
  606. t.Helper()
  607. t.Run(name, func(t *testing.T) {
  608. actual := SortedKeys(input)
  609. if !reflect.DeepEqual(actual, expected) {
  610. t.Errorf("expected %v, got %v", expected, actual)
  611. }
  612. })
  613. }
  614. func TestSortedKeys(t *testing.T) {
  615. testSortedKeysHelper(t, "simple", map[string]string{
  616. "b": "bar",
  617. "a": "foo",
  618. }, []string{
  619. "a",
  620. "b",
  621. })
  622. testSortedKeysHelper(t, "ints", map[int]interface{}{
  623. 10: nil,
  624. 5: nil,
  625. }, []int{
  626. 5,
  627. 10,
  628. })
  629. testSortedKeysHelper(t, "nil", map[string]string(nil), nil)
  630. testSortedKeysHelper(t, "empty", map[string]string{}, nil)
  631. }
  632. func TestSortedStringValues(t *testing.T) {
  633. testCases := []struct {
  634. name string
  635. in interface{}
  636. expected []string
  637. }{
  638. {
  639. name: "nil",
  640. in: map[string]string(nil),
  641. expected: nil,
  642. },
  643. {
  644. name: "empty",
  645. in: map[string]string{},
  646. expected: nil,
  647. },
  648. {
  649. name: "simple",
  650. in: map[string]string{"foo": "a", "bar": "b"},
  651. expected: []string{"a", "b"},
  652. },
  653. {
  654. name: "duplicates",
  655. in: map[string]string{"foo": "a", "bar": "b", "baz": "b"},
  656. expected: []string{"a", "b", "b"},
  657. },
  658. }
  659. for _, tt := range testCases {
  660. t.Run(tt.name, func(t *testing.T) {
  661. got := SortedStringValues(tt.in)
  662. if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
  663. t.Errorf("wanted %q, got %q", w, g)
  664. }
  665. })
  666. }
  667. }
  668. func TestSortedUniqueStringValues(t *testing.T) {
  669. testCases := []struct {
  670. name string
  671. in interface{}
  672. expected []string
  673. }{
  674. {
  675. name: "nil",
  676. in: map[string]string(nil),
  677. expected: nil,
  678. },
  679. {
  680. name: "empty",
  681. in: map[string]string{},
  682. expected: nil,
  683. },
  684. {
  685. name: "simple",
  686. in: map[string]string{"foo": "a", "bar": "b"},
  687. expected: []string{"a", "b"},
  688. },
  689. {
  690. name: "duplicates",
  691. in: map[string]string{"foo": "a", "bar": "b", "baz": "b"},
  692. expected: []string{"a", "b"},
  693. },
  694. }
  695. for _, tt := range testCases {
  696. t.Run(tt.name, func(t *testing.T) {
  697. got := SortedUniqueStringValues(tt.in)
  698. if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
  699. t.Errorf("wanted %q, got %q", w, g)
  700. }
  701. })
  702. }
  703. }