Skip to content

Commit 6b3b588

Browse files
committed
utils: implement 'Map()'
Implement a basic list-mapping function for input/output lists of arbitrary types. Add unit tests covering a variety of input/output types and map functions. Signed-off-by: Victoria Dye <[email protected]>
1 parent f64602c commit 6b3b588

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

internal/utils/slices.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package utils
2+
3+
// Utility functions for slices not built into the standard library
4+
5+
func Map[T any, S any](in []T, fn func(t T) S) []S {
6+
out := make([]S, len(in))
7+
for i, t := range in {
8+
out[i] = fn(t)
9+
}
10+
return out
11+
}

internal/utils/slices_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package utils_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/github/git-bundle-server/internal/utils"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
// To test generics, implement the general-purpose 'testable' interface in
12+
// a templated, function-specific struct (like 'mapTest') that define how
13+
// the associated generic function is tested.
14+
15+
type testable interface {
16+
runTest(t *testing.T)
17+
}
18+
19+
type mapTest[T any, S any] struct {
20+
title string
21+
22+
// Inputs
23+
in []T
24+
fn func(T) S
25+
26+
// Outputs
27+
expectedOut []S
28+
}
29+
30+
type twoInts struct {
31+
int1 int
32+
int2 int
33+
}
34+
35+
var mapTests = []testable{
36+
mapTest[string, string]{
37+
title: "string -> string",
38+
39+
in: []string{" A ", "B\t", "\nC \r\n", "D", " E\t"},
40+
fn: strings.TrimSpace,
41+
42+
expectedOut: []string{"A", "B", "C", "D", "E"},
43+
},
44+
mapTest[int, float32]{
45+
title: "int -> float32",
46+
47+
in: []int{1, 2, 3, 4, 5},
48+
fn: func(i int) float32 { return float32(i) },
49+
50+
expectedOut: []float32{1, 2, 3, 4, 5},
51+
},
52+
mapTest[string, struct{ name string }]{
53+
title: "string -> anonymous struct",
54+
55+
in: []string{"test", "another test"},
56+
fn: func(str string) struct{ name string } { return struct{ name string }{name: str} },
57+
58+
expectedOut: []struct{ name string }{{name: "test"}, {name: "another test"}},
59+
},
60+
mapTest[twoInts, int]{
61+
title: "named struct -> int",
62+
63+
in: []twoInts{{int1: 12, int2: 34}, {int1: 56, int2: 78}},
64+
fn: func(s twoInts) int { return s.int1 + s.int2 },
65+
66+
expectedOut: []int{46, 134},
67+
},
68+
}
69+
70+
func (tt mapTest[T, S]) runTest(t *testing.T) {
71+
t.Run(tt.title, func(t *testing.T) {
72+
out := utils.Map(tt.in, tt.fn)
73+
assert.Equal(t, tt.expectedOut, out)
74+
})
75+
}
76+
77+
func TestMap(t *testing.T) {
78+
for _, tt := range mapTests {
79+
tt.runTest(t)
80+
}
81+
}

0 commit comments

Comments
 (0)