From 0f448b7c87cc06b03978cc5c50c11bb161a55948 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Wed, 22 May 2024 16:06:48 +0000 Subject: [PATCH] refactor: add comparisons pkg for reused helpers This commit moves the helper functions from provider.go to a new comparisons package. This package will be used by provider, tests, and resources. The refactoring will assist with splitting resources into resource specific packages. The previous helper functions have been deprecated and will be removed in a future commit. Signed-off-by: Marques Johansson --- equinix/provider.go | 12 ++++ internal/comparisons/comparisons.go | 67 ++++++++++++++++++ internal/comparisons/comparisons_test.go | 89 ++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 internal/comparisons/comparisons.go create mode 100644 internal/comparisons/comparisons_test.go diff --git a/equinix/provider.go b/equinix/provider.go index 46275dc5d..b300753c3 100644 --- a/equinix/provider.go +++ b/equinix/provider.go @@ -193,6 +193,10 @@ func configureProvider(ctx context.Context, d *schema.ResourceData, p *schema.Pr return &config, nil } +// stringsFound returns true if all strings in source are found in target +// Deprecated: stringsFound is shared between provider, tests, and resources +// and is being relocated for package refactoring. +// Use github.com/equinix/terraform-provider-equinix/internal/comparisons.Subsets func stringsFound(source []string, target []string) bool { for i := range source { if !slices.Contains(target, source[i]) { @@ -202,6 +206,10 @@ func stringsFound(source []string, target []string) bool { return true } +// isEmpty returns true if the value is nil or zero +// Deprecated: isEmpty is shared between provider, tests, and resources +// and is being relocated for package refactoring. +// Use github.com/equinix/terraform-provider-equinix/internal/comparisons.IsEmpty func isEmpty(v interface{}) bool { switch v := v.(type) { case int: @@ -219,6 +227,10 @@ func isEmpty(v interface{}) bool { } } +// slicesMatch returns true if all strings in s1 are found in s2 +// Deprecated: slicesMatch is shared between provider, tests, and resources +// and is being relocated for package refactoring. +// Use github.com/equinix/terraform-provider-equinix/internal/comparisons.SlicesMatch func slicesMatch(s1, s2 []string) bool { if len(s1) != len(s2) { return false diff --git a/internal/comparisons/comparisons.go b/internal/comparisons/comparisons.go new file mode 100644 index 000000000..351c173c2 --- /dev/null +++ b/internal/comparisons/comparisons.go @@ -0,0 +1,67 @@ +package comparisons + +import ( + "cmp" + "slices" + "strings" +) + +// isEmpty returns true if the given value is empty +func isEmpty(v interface{}) bool { + switch v := v.(type) { + case int: + return v == 0 + case *int: + return v == nil || *v == 0 + case string: + return v == "" + case *string: + return v == nil || *v == "" + case nil: + return true + default: + return false + } +} + +// Subsets returns true if the first slice is a subset of the second slice +func Subsets[T cmp.Ordered](s1, s2 []T) bool { + // Iterate over the first slice + for _, e := range s1 { + // If the element is not in the second slice, return false + if !slices.Contains(s2, e) { + return false + } + } + + return true +} + +// comparisons.SlicesMatch returns true if the two slices contain the same elements, regardless of order +func SlicesMatch[T cmp.Ordered](s1, s2 []T) bool { + if len(s1) != len(s2) { + return false + } + + // Create copies of the slices to avoid mutating the input slices + s1Copy := append([]T(nil), s1...) + s2Copy := append([]T(nil), s2...) + + // Sort the slices + slices.Sort(s1Copy) + slices.Sort(s2Copy) + + return slices.Equal(s1Copy, s2Copy) +} + +// caseInsensitiveLess is a comparison function for sorting strings case-insensitively +func caseInsensitiveLess(s1, s2 string) int { + switch { + case strings.ToLower(s1) == strings.ToLower(s2): + return 0 + case strings.ToLower(s1) < strings.ToLower(s2): + return -1 + default: + return 1 + } +} diff --git a/internal/comparisons/comparisons_test.go b/internal/comparisons/comparisons_test.go new file mode 100644 index 000000000..f0a552f54 --- /dev/null +++ b/internal/comparisons/comparisons_test.go @@ -0,0 +1,89 @@ +package comparisons_test + +import ( + "testing" + + "github.com/equinix/terraform-provider-equinix/internal/comparisons" + "github.com/stretchr/testify/assert" +) + +func TestSubsets(t *testing.T) { + // given + needles := []string{"key1", "key5"} + hay := []string{"key1", "key2", "Key3", "key4", "key5"} + // when + result := comparisons.Subsets(needles, hay) + // then + assert.True(t, result, "Given strings were found") +} + +func TestSubsets_negative(t *testing.T) { + // given + needles := []string{"key1", "key6"} + hay := []string{"key1", "key2", "Key3", "key4", "key5"} + // when + result := comparisons.Subsets(hay, needles) + // then + assert.False(t, result, "Given strings were found") +} + +func TestIsEmpty(t *testing.T) { + // given + input := []interface{}{ + "test", + "", + nil, + 123, + 0, + 43.43, + } + expected := []bool{ + false, + true, + true, + false, + true, + false, + true, + } + // when then + for i := range input { + assert.Equal(t, expected[i], comparisons.IsEmpty(input[i]), "Input %v produces expected result %v", input[i], expected[i]) + } +} + +func TestSlicesMatch(t *testing.T) { + // given + input := [][][]string{ + { + {"DC", "SV", "FR"}, + {"FR", "SV", "DC"}, + }, + { + {"SV"}, + {}, + }, + { + {"DC", "DC", "DC"}, + {"DC", "SV", "DC"}, + }, + { + {}, {}, + }, + } + expected := []bool{ + true, + false, + false, + true, + } + // when + results := make([]bool, len(expected)) + for i := range input { + results[i] = comparisons.SlicesMatch(input[i][0], input[i][1]) + } + // then + for i := range expected { + assert.Equal(t, expected[i], results[i]) + } +}