I'm playing around with go generics by modifying a library I created for working with slices. I have a Difference function which accepts slices and returns a list of unique elements only found in one of the slices.
I modified the function to use generics and I'm trying to write unit tests with different types (e.g. strings and ints) but am having trouble with the union type. Here's what I have, now:
type testDifferenceInput[T comparable] [][]T
type testDifferenceOutput[T comparable] []T
type testDifference[T comparable] struct {
input testDifferenceInput[T]
output testDifferenceOutput[T]
}
func TestDifference(t *testing.T) {
for i, tt := range []testDifference[int] {
testDifference[int]{
input: testDifferenceInput[int]{
[]int{1, 2, 3, 3, 4},
[]int{1, 2, 5},
[]int{1, 3, 6},
},
output: []int{4, 5, 6},
},
} {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
actual := Difference(tt.input...)
if !isEqual(actual, tt.output) {
t.Errorf("expected: %v %T, received: %v %T", tt.output, tt.output, actual, actual)
}
})
}
}
I would like to be able to test both int's or string's in the same table test. Here's what I've tried:
type intOrString interface {
int | string
}
type testDifferenceInput[T comparable] [][]T
type testDifferenceOutput[T comparable] []T
type testDifference[T comparable] struct {
input testDifferenceInput[T]
output testDifferenceOutput[T]
}
func TestDifference(t *testing.T) {
for i, tt := range []testDifference[intOrString] {
testDifference[int]{
input: testDifferenceInput[int]{
[]int{1, 2, 3, 3, 4},
[]int{1, 2, 5},
[]int{1, 3, 6},
},
output: []int{4, 5, 6},
},
testDifference[string]{
input: testDifferenceInput[string]{
[]string{"1", "2", "3", "3", "4"},
[]string{"1", "2", "5"},
[]string{"1", "3", "6"},
},
output: []string{"4", "5", "6"},
},
} {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
actual := Difference(tt.input...)
if !isEqual(actual, tt.output) {
t.Errorf("expected: %v %T, received: %v %T", tt.output, tt.output, actual, actual)
}
})
}
}
However, when running this, I get the following error:
$ go version
go version dev.go2go-55626ee50b linux/amd64
$ go tool go2go test
arrayOperations_unit_test.go2:142:6: expected ';', found '|' (and 5 more errors)
Why is it complaining about my intOrString interface?
EDIT #1 - I can confirm, with @Nulo's help, that gotip does work, and I now understand why I can't use intOrString as a type - it's supposed to be a constraint.
However, it would still be nice to find some way to mix ints and strings in my table test...
$ gotip version
go version devel go1.18-c812b97 Fri Oct 29 22:29:31 2021 +0000 linux/amd64
$ gotip test
# github.com/adam-hanna/arrayOperations/go2 [github.com/adam-hanna/arrayOperations/go2.test]
./arrayOperations_unit_test.go:152:39: interface contains type constraints
./arrayOperations_unit_test.go:152:39: intOrString does not satisfy intOrString
./arrayOperations_unit_test.go:155:6: incompatible type: cannot use []int{…} (value of type []int) as []intOrString value
./arrayOperations_unit_test.go:156:6: incompatible type: cannot use []int{…} (value of type []int) as []intOrString value
./arrayOperations_unit_test.go:157:6: incompatible type: cannot use []int{…} (value of type []int) as []intOrString value
./arrayOperations_unit_test.go:159:13: incompatible type: cannot use []int{…} (value of type []int) as testDifferenceOutput[intOrString] value
./arrayOperations_unit_test.go:163:6: incompatible type: cannot use []string{…} (value of type []string) as []intOrString value
./arrayOperations_unit_test.go:164:6: incompatible type: cannot use []string{…} (value of type []string) as []intOrString value
./arrayOperations_unit_test.go:165:6: incompatible type: cannot use []string{…} (value of type []string) as []intOrString value
./arrayOperations_unit_test.go:167:13: incompatible type: cannot use []string{…} (value of type []string) as testDifferenceOutput[intOrString] value
./arrayOperations_unit_test.go:152:39: too many errors
FAIL github.com/adam-hanna/arrayOperations/go2 [build failed]