From d95c11adf70dc56aeb03d298ced0c13ed4d67de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Anda=20Estensen?= Date: Fri, 8 Dec 2023 08:35:40 +0100 Subject: [PATCH 1/6] Test slices functions --- utils/slices_test.go | 110 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 utils/slices_test.go diff --git a/utils/slices_test.go b/utils/slices_test.go new file mode 100644 index 00000000..afe1469f --- /dev/null +++ b/utils/slices_test.go @@ -0,0 +1,110 @@ +package utils + +import ( + "fmt" + "reflect" + "testing" +) + +func TestFlatten(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input [][]int + expected []int + }{ + { + name: "nil slice", + input: nil, + expected: nil, + }, + { + name: "empty slices", + input: [][]int{{}}, + expected: nil, + }, + { + name: "single slice", + input: [][]int{{1, 2, 3}}, + expected: []int{1, 2, 3}, + }, + { + name: "multiple slices", + input: [][]int{{1, 2}, {3, 4}, {5}}, + expected: []int{1, 2, 3, 4, 5}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + result := Flatten(tc.input...) + if !reflect.DeepEqual(result, tc.expected) { + t.Errorf("Flatten(%v) = %v, want %v", tc.input, result, tc.expected) + } + }) + } +} + +func TestMap(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input []int + expected []string + }{ + { + name: "empty slice", + input: []int{}, + expected: []string{}, + }, + { + name: "non-empty slice", + input: []int{1, 2, 3}, + expected: []string{"1", "2", "3"}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + result := Map(tc.input, func(i int) string { return fmt.Sprintf("%d", i) }) + if !reflect.DeepEqual(result, tc.expected) { + t.Errorf("Map(%v) = %v, want %v", tc.input, result, tc.expected) + } + }) + } +} + +func TestFilter(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input []int + expected []int + }{ + { + name: "empty slice", + input: []int{}, + expected: []int{}, + }, + { + name: "filter even numbers", + input: []int{1, 2, 3, 4, 5}, + expected: []int{2, 4}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + result := Filter(tc.input, func(i int) bool { return i%2 == 0 }) + if !reflect.DeepEqual(result, tc.expected) { + t.Errorf("Filter(%v) = %v, want %v", tc.input, result, tc.expected) + } + }) + } +} From 818024b66cf1bd5b0c84692d8c1153c4d2410610 Mon Sep 17 00:00:00 2001 From: thiagodeev Date: Wed, 2 Apr 2025 16:49:07 -0300 Subject: [PATCH 2/6] 'utils' slices_test.go moved to 'internal' pgk --- {utils => internal/utils}/slices_test.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {utils => internal/utils}/slices_test.go (100%) diff --git a/utils/slices_test.go b/internal/utils/slices_test.go similarity index 100% rename from utils/slices_test.go rename to internal/utils/slices_test.go From fde5319770c1f2962732a8cf9ee8ae3fd1c0bb43 Mon Sep 17 00:00:00 2001 From: thiagodeev Date: Wed, 2 Apr 2025 16:52:30 -0300 Subject: [PATCH 3/6] TestFlatten improved --- internal/utils/slices_test.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/utils/slices_test.go b/internal/utils/slices_test.go index afe1469f..5dddfc84 100644 --- a/internal/utils/slices_test.go +++ b/internal/utils/slices_test.go @@ -4,6 +4,8 @@ import ( "fmt" "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestFlatten(t *testing.T) { @@ -34,15 +36,23 @@ func TestFlatten(t *testing.T) { input: [][]int{{1, 2}, {3, 4}, {5}}, expected: []int{1, 2, 3, 4, 5}, }, + { + name: "mixed empty and non-empty slices", + input: [][]int{{}, {1, 2}, {}, {3}, {}}, + expected: []int{1, 2, 3}, + }, + { + name: "all empty slices", + input: [][]int{{}, {}, {}}, + expected: nil, + }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { result := Flatten(tc.input...) - if !reflect.DeepEqual(result, tc.expected) { - t.Errorf("Flatten(%v) = %v, want %v", tc.input, result, tc.expected) - } + assert.ElementsMatch(t, result, tc.expected) }) } } From 45e30b53943144dd443bee0bacf7afeafd0c5860 Mon Sep 17 00:00:00 2001 From: thiagodeev Date: Wed, 2 Apr 2025 17:01:01 -0300 Subject: [PATCH 4/6] TestMap improved --- internal/utils/slices_test.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/internal/utils/slices_test.go b/internal/utils/slices_test.go index 5dddfc84..a8ea4dab 100644 --- a/internal/utils/slices_test.go +++ b/internal/utils/slices_test.go @@ -65,6 +65,11 @@ func TestMap(t *testing.T) { input []int expected []string }{ + { + name: "nil slice", + input: nil, + expected: nil, + }, { name: "empty slice", input: []int{}, @@ -75,15 +80,18 @@ func TestMap(t *testing.T) { input: []int{1, 2, 3}, expected: []string{"1", "2", "3"}, }, + { + name: "single element", + input: []int{42}, + expected: []string{"42"}, + }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { result := Map(tc.input, func(i int) string { return fmt.Sprintf("%d", i) }) - if !reflect.DeepEqual(result, tc.expected) { - t.Errorf("Map(%v) = %v, want %v", tc.input, result, tc.expected) - } + assert.ElementsMatch(t, result, tc.expected) }) } } From 5053370545386df91cb6462e33998a4a9767b1f8 Mon Sep 17 00:00:00 2001 From: thiagodeev Date: Wed, 2 Apr 2025 17:05:01 -0300 Subject: [PATCH 5/6] Improve Filter and TestFilter --- internal/utils/slices.go | 12 +++++++++++- internal/utils/slices_test.go | 25 +++++++++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/internal/utils/slices.go b/internal/utils/slices.go index 00e7cd6b..b226a803 100644 --- a/internal/utils/slices.go +++ b/internal/utils/slices.go @@ -2,6 +2,7 @@ package utils import "slices" +// Flatten flattens a slice of slices into a single slice func Flatten[T any](sl ...[]T) []T { var result []T for _, slice := range sl { @@ -11,6 +12,7 @@ func Flatten[T any](sl ...[]T) []T { return result } +// Map maps a slice of type T1 to a slice of type T2 using the given function func Map[T1, T2 any](slice []T1, f func(T1) T2) []T2 { if slice == nil { return nil @@ -24,8 +26,16 @@ func Map[T1, T2 any](slice []T1, f func(T1) T2) []T2 { return result } +// Filter filters a slice of type T using the given predicate, returning a new slice with the elements that match the predicate func Filter[T any](slice []T, f func(T) bool) []T { - var result []T + if slice == nil { + return nil + } + if len(slice) == 0 { + return slice + } + + result := make([]T, 0) for _, e := range slice { if f(e) { result = append(result, e) diff --git a/internal/utils/slices_test.go b/internal/utils/slices_test.go index a8ea4dab..176cc5e8 100644 --- a/internal/utils/slices_test.go +++ b/internal/utils/slices_test.go @@ -2,7 +2,6 @@ package utils import ( "fmt" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -104,6 +103,11 @@ func TestFilter(t *testing.T) { input []int expected []int }{ + { + name: "nil slice", + input: nil, + expected: nil, + }, { name: "empty slice", input: []int{}, @@ -114,15 +118,28 @@ func TestFilter(t *testing.T) { input: []int{1, 2, 3, 4, 5}, expected: []int{2, 4}, }, + { + name: "no matches", + input: []int{1, 3, 5, 7, 9}, + expected: []int{}, + }, + { + name: "all matches", + input: []int{2, 4, 6, 8, 10}, + expected: []int{2, 4, 6, 8, 10}, + }, + { + name: "single element match", + input: []int{1, 2, 3}, + expected: []int{2}, + }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { result := Filter(tc.input, func(i int) bool { return i%2 == 0 }) - if !reflect.DeepEqual(result, tc.expected) { - t.Errorf("Filter(%v) = %v, want %v", tc.input, result, tc.expected) - } + assert.ElementsMatch(t, result, tc.expected) }) } } From 6877d0de1d447cde77a1816f11b3e16c65167feb Mon Sep 17 00:00:00 2001 From: thiagodeev Date: Wed, 2 Apr 2025 17:06:10 -0300 Subject: [PATCH 6/6] Add TestAll test --- internal/utils/slices_test.go | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/internal/utils/slices_test.go b/internal/utils/slices_test.go index 176cc5e8..68978a26 100644 --- a/internal/utils/slices_test.go +++ b/internal/utils/slices_test.go @@ -143,3 +143,65 @@ func TestFilter(t *testing.T) { }) } } + +func TestAll(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input []int + pred func(int) bool + expected bool + }{ + { + name: "nil slice", + input: nil, + pred: func(i int) bool { return true }, + expected: true, + }, + { + name: "empty slice", + input: []int{}, + pred: func(i int) bool { return true }, + expected: true, + }, + { + name: "all even numbers", + input: []int{2, 4, 6, 8, 10}, + pred: func(i int) bool { return i%2 == 0 }, + expected: true, + }, + { + name: "mixed numbers", + input: []int{2, 3, 4, 6, 8}, + pred: func(i int) bool { return i%2 == 0 }, + expected: false, + }, + { + name: "all odd numbers", + input: []int{1, 3, 5, 7, 9}, + pred: func(i int) bool { return i%2 == 1 }, + expected: true, + }, + { + name: "single element true", + input: []int{2}, + pred: func(i int) bool { return i%2 == 0 }, + expected: true, + }, + { + name: "single element false", + input: []int{1}, + pred: func(i int) bool { return i%2 == 0 }, + expected: false, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + result := All(tc.input, tc.pred) + assert.Equal(t, result, tc.expected) + }) + } +}