mirror of
https://github.com/rancher/os.git
synced 2025-08-02 07:24:28 +00:00
slices union and intersection
useful for merging and splitting configs
This commit is contained in:
parent
974206235d
commit
4d6530be73
@ -10,55 +10,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestNilMap(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
var m map[string]interface{} = nil
|
||||
assert.True(m == nil)
|
||||
}
|
||||
|
||||
func TestMapCopy(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
||||
m1 := util.MapCopy(m0)
|
||||
|
||||
delete(m0, "a")
|
||||
assert.Equal(len(m1), len(m0)+1)
|
||||
|
||||
b0 := m0["b"].(map[interface{}]interface{})
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
b1["e"] = "queer"
|
||||
|
||||
assert.Equal(len(b1), len(b0)+1)
|
||||
}
|
||||
|
||||
func TestMapsIntersection(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
||||
m1 := util.MapCopy(m0)
|
||||
|
||||
delete(m0, "a")
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
delete(b1, "c")
|
||||
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4"}
|
||||
assert.Equal(expected, util.MapsIntersection(m0, m1, util.Equal))
|
||||
}
|
||||
|
||||
func TestMapsUnion(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
||||
m1 := util.MapCopy(m0)
|
||||
m1["e"] = "added"
|
||||
m1["d"] = "replaced"
|
||||
|
||||
delete(m0, "a")
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
delete(b1, "c")
|
||||
expected := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "replaced", "e": "added"}
|
||||
assert.Equal(expected, util.MapsUnion(m0, m1, util.Replace))
|
||||
}
|
||||
|
||||
func TestFilterKey(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
data := map[interface{}]interface{}{
|
||||
|
69
util/util.go
69
util/util.go
@ -181,6 +181,8 @@ func Copy(d interface{}) interface{} {
|
||||
switch d := d.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
return MapCopy(d)
|
||||
case []interface{}:
|
||||
return SliceCopy(d)
|
||||
default:
|
||||
return d
|
||||
}
|
||||
@ -197,11 +199,40 @@ func Equal(l, r interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExistsIn(x interface{}, s []interface{}) bool {
|
||||
for _, y := range s {
|
||||
if reflect.DeepEqual(x, y) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func SlicesUnion(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
||||
result := SliceCopy(left)
|
||||
for _, r := range right {
|
||||
if !ExistsIn(r, result) {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func SlicesIntersection(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
||||
result := []interface{}{}
|
||||
for _, r := range right {
|
||||
if ExistsIn(r, left) {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
|
||||
result := MapCopy(left)
|
||||
|
||||
for k, r := range right {
|
||||
if l, ok := result[k]; ok {
|
||||
if l, ok := left[k]; ok {
|
||||
switch l := l.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
switch r := r.(type) {
|
||||
@ -210,6 +241,13 @@ func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, int
|
||||
default:
|
||||
result[k] = op(l, r)
|
||||
}
|
||||
case []interface{}:
|
||||
switch r := r.(type) {
|
||||
case []interface{}:
|
||||
result[k] = SlicesUnion(l, r, op)
|
||||
default:
|
||||
result[k] = op(l, r)
|
||||
}
|
||||
default:
|
||||
result[k] = op(l, r)
|
||||
}
|
||||
@ -226,19 +264,28 @@ func MapsIntersection(left, right map[interface{}]interface{}, op func(interface
|
||||
|
||||
for k, l := range left {
|
||||
if r, ok := right[k]; ok {
|
||||
switch r := r.(type) {
|
||||
switch l := l.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
switch l := l.(type) {
|
||||
switch r := r.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
result[k] = MapsIntersection(l, r, op)
|
||||
default:
|
||||
if i := op(l, r); i != nil {
|
||||
result[k] = i
|
||||
if v := op(l, r); v != nil {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
case []interface{}:
|
||||
switch r := r.(type) {
|
||||
case []interface{}:
|
||||
result[k] = SlicesIntersection(l, r, op)
|
||||
default:
|
||||
if v := op(l, r); v != nil {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
default:
|
||||
if i := op(l, r); i != nil {
|
||||
result[k] = i
|
||||
if v := op(l, r); v != nil {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,6 +302,14 @@ func MapCopy(data map[interface{}]interface{}) map[interface{}]interface{} {
|
||||
return result
|
||||
}
|
||||
|
||||
func SliceCopy(data []interface{}) []interface{} {
|
||||
result := make([]interface{}, len(data), len(data))
|
||||
for k, v := range data {
|
||||
result[k] = Copy(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func GetServices(urls []string) ([]string, error) {
|
||||
result := []string{}
|
||||
|
||||
|
@ -6,6 +6,90 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNilMap(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
var m map[string]interface{} = nil
|
||||
assert.True(m == nil)
|
||||
}
|
||||
|
||||
func TestMapCopy(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
||||
m1 := MapCopy(m0)
|
||||
assert.Equal(m0, m1)
|
||||
|
||||
delete(m0, "a")
|
||||
assert.Equal(len(m1), len(m0)+1)
|
||||
|
||||
b0 := m0["b"].(map[interface{}]interface{})
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
b1["e"] = "queer"
|
||||
|
||||
assert.Equal(len(b1), len(b0)+1)
|
||||
}
|
||||
|
||||
func TestSliceCopy(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
m0 := []interface{}{1, map[interface{}]interface{}{"c": 3}, "4"}
|
||||
m1 := SliceCopy(m0)
|
||||
assert.Equal(m0, m1)
|
||||
|
||||
m0 = m0[1:]
|
||||
assert.Equal(len(m1), len(m0)+1)
|
||||
|
||||
b0 := m0[0].(map[interface{}]interface{})
|
||||
b1 := m1[1].(map[interface{}]interface{})
|
||||
b1["e"] = "queer"
|
||||
|
||||
assert.Equal(len(b1), len(b0)+1)
|
||||
}
|
||||
|
||||
func TestMapsIntersection(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
m0 := map[interface{}]interface{}{
|
||||
"a": 1,
|
||||
"b": map[interface{}]interface{}{"c": 3},
|
||||
"d": "4",
|
||||
"e": []interface{}{1, 2, 3},
|
||||
}
|
||||
m1 := MapCopy(m0)
|
||||
|
||||
delete(m0, "a")
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
delete(b1, "c")
|
||||
m1["e"] = []interface{}{2, 3, 4}
|
||||
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4", "e": []interface{}{2, 3}}
|
||||
assert.Equal(expected, MapsIntersection(m0, m1, Equal))
|
||||
}
|
||||
|
||||
func TestMapsUnion(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
m0 := map[interface{}]interface{}{
|
||||
"a": 1,
|
||||
"b": map[interface{}]interface{}{"c": 3},
|
||||
"d": "4",
|
||||
"f": []interface{}{1, 2, 3},
|
||||
}
|
||||
m1 := MapCopy(m0)
|
||||
m1["e"] = "added"
|
||||
m1["d"] = "replaced"
|
||||
m1["f"] = []interface{}{2, 3, 4}
|
||||
|
||||
delete(m0, "a")
|
||||
b1 := m1["b"].(map[interface{}]interface{})
|
||||
delete(b1, "c")
|
||||
expected := map[interface{}]interface{}{
|
||||
"a": 1,
|
||||
"b": map[interface{}]interface{}{"c": 3},
|
||||
"d": "replaced",
|
||||
"e": "added",
|
||||
"f": []interface{}{1, 2, 3, 4},
|
||||
}
|
||||
assert.Equal(expected, MapsUnion(m0, m1, Replace))
|
||||
}
|
||||
|
||||
func TestLoadResourceSimple(t *testing.T) {
|
||||
assert := require.New(t)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user