├── .gitignore ├── utils.go ├── .travis.yml ├── LICENSE ├── mapop.go ├── README.md └── mapop_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package mapop 2 | 3 | func includes(k string, keys ...string) bool { 4 | for _, key := range keys { 5 | if key == k { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | 12 | func selectORreject(reject bool, input map[string]interface{}, keys ...string) (output map[string]interface{}) { 13 | size := len(input) 14 | keysSize := len(keys) 15 | if size <= 0 { 16 | return nil 17 | } 18 | if keysSize <= 0 { 19 | return input 20 | } 21 | if size >= keysSize { 22 | size = size - keysSize 23 | } 24 | output = make(map[string]interface{}, size) 25 | for key, value := range input { 26 | if reject { 27 | if !includes(key, keys...) { 28 | output[key] = value 29 | } 30 | } else { 31 | if includes(key, keys...) { 32 | output[key] = value 33 | } 34 | } 35 | } 36 | return output 37 | } 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5 5 | 6 | evn: 7 | - GO15VENDOREXPERIMENT=1 8 | - secure: "BLUzKR7OHzI2jBR+Mo0CoyazvtpOaLn06dIcr1xI756x/AqlmDp7eV0u+h1r7EKMLppdCUHfkiFsPm9bQyMBELo4rT6l8XNjeWY46L9Ky3Il93g5PMNUI9H3nABiST9d7myPjE4139z2CAeyHwXtoObISEhpYjqgec0IecXzpSbQjOjUxRAdbNfXhHtK1lKvhy5IgUbGIG5u+Vlj+Tub6bO8fJWifRSwnl/mT0Ow3VYmh2bI7luH+kdv0tbxj+3d0h7F3UY5EFEDB2/ZDNA0AFZB8YZWbuD2lUX53x7dGNIzxvJMUEW0aL4uQrfd0t8LZFs9k5tuoFaaC1SpzXWagX4mqw0THpWw+mL1gI1xzcqf7UriLIllgtv96CPHB1UO9n2kkpocyXpf+rcQviqMgFakzBp9q8wDiBn7bX39FZyHusX73B172uiY/8kA2q/clck70KhycHg4nha2atT7w4OqnnlOEzxxhy0inqcjyWYmXtBDzYFN+4HFH6t5zkylLJvD/ag2j7lNO4NKLf3C0WbCycF5H+tY5FNOuq6VTJjMFzoH2m5xRti5Bfp1F0MqlIPAse1g9McWCmFYDr3LXVx4VnozqDt9ue85o+EvhHkQhraTEUSSb8k9T1dLpfaLGukr+CIbA5BVOAzISQ3f5HL51WBxlDZXVE3M7rt95MM=" 9 | 10 | before_install: 11 | - go get -v golang.org/x/tools/cmd/cover 12 | - go get -v github.com/golang/lint/golint 13 | - go get -v github.com/Sirupsen/logrus 14 | - go get -v github.com/stretchr/testify/assert 15 | - go get -v github.com/mattn/goveralls 16 | 17 | install: 18 | - go install -race -v std 19 | - go get -race -t -v ./... 20 | - go install -race -v ./... 21 | 22 | script: 23 | - $HOME/gopath/bin/golint . 24 | - go test -cpu=2 -race -v ./... 25 | - go test -cpu=2 -covermode=atomic ./... 26 | - go test -v -covermode=count -coverprofile=coverage.out 27 | - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, linkosmos 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of mapop nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /mapop.go: -------------------------------------------------------------------------------- 1 | package mapop 2 | 3 | // Split - split map string<=>interface to ordered keys and values 4 | func Split(input map[string]interface{}) (keys []string, values []interface{}) { 5 | size := len(input) 6 | if size <= 0 { 7 | return nil, nil 8 | } 9 | keys = make([]string, 0, size) 10 | values = make([]interface{}, 0, size) 11 | for key, value := range input { 12 | keys = append(keys, key) 13 | values = append(values, value) 14 | } 15 | return keys, values 16 | } 17 | 18 | // Keys - return map keys 19 | func Keys(input map[string]interface{}) (keys []string) { 20 | keys, _ = Split(input) 21 | return keys 22 | } 23 | 24 | // Values - return map values 25 | func Values(input map[string]interface{}) (values []interface{}) { 26 | _, values = Split(input) 27 | return values 28 | } 29 | 30 | // Select - select specified keys from map and get new map 31 | func Select(input map[string]interface{}, keys ...string) map[string]interface{} { 32 | return selectORreject(false, input, keys...) 33 | } 34 | 35 | // Reject - reject specified keys from map and get new map 36 | func Reject(input map[string]interface{}, keys ...string) map[string]interface{} { 37 | return selectORreject(true, input, keys...) 38 | } 39 | 40 | // MapKeys - maps map keys, values remain unchanged and associated 41 | func MapKeys(f func(string) string, input map[string]interface{}) (output map[string]interface{}) { 42 | size := len(input) 43 | if size == 0 { 44 | return input 45 | } 46 | output = make(map[string]interface{}, size) 47 | for key, value := range input { 48 | output[f(key)] = value 49 | } 50 | return output 51 | } 52 | 53 | // MapValues - maps map values, keys and values association remains unchanged 54 | func MapValues(f func(interface{}) interface{}, input map[string]interface{}) (output map[string]interface{}) { 55 | size := len(input) 56 | if size == 0 { 57 | return input 58 | } 59 | output = make(map[string]interface{}, size) 60 | for key, value := range input { 61 | output[key] = f(value) 62 | } 63 | return output 64 | } 65 | 66 | // Partition - returns two maps in array, the first containing the elements 67 | // for which the function evaluates to true, the second containing the rest. 68 | func Partition(f func(string, interface{}) bool, input map[string]interface{}) (partition []map[string]interface{}) { 69 | partition = make([]map[string]interface{}, 2) 70 | size := len(input) 71 | if size == 0 { 72 | partition[0] = input 73 | partition[1] = nil 74 | return partition 75 | } 76 | // Assuming half of key values will be partitioned 77 | partition[0] = make(map[string]interface{}, size/2) 78 | partition[1] = make(map[string]interface{}, size/2) 79 | for key, value := range input { 80 | if f(key, value) { 81 | partition[0][key] = value 82 | } else { 83 | partition[1][key] = value 84 | } 85 | } 86 | return partition 87 | } 88 | 89 | // Map - maps key or values as defined in function 90 | func Map(f func(key string, value interface{}) (string, interface{}), input map[string]interface{}) (output map[string]interface{}) { 91 | size := len(input) 92 | if size == 0 { 93 | return input 94 | } 95 | output = make(map[string]interface{}, size) 96 | var mappedKey string 97 | var mappedValue interface{} 98 | for key, value := range input { 99 | mappedKey, mappedValue = f(key, value) 100 | output[mappedKey] = mappedValue 101 | } 102 | return output 103 | } 104 | 105 | // Collect - removes all nil interface values and returns clean map 106 | func Collect(input map[string]interface{}) (output map[string]interface{}) { 107 | size := len(input) 108 | if size == 0 { 109 | return input 110 | } 111 | output = make(map[string]interface{}, size) 112 | for key, value := range input { 113 | if value != nil { 114 | output[key] = value 115 | } 116 | } 117 | return output 118 | } 119 | 120 | // Merge - merges given maps into 1 map 121 | // values will be overridden by last matching key - value 122 | func Merge(maps ...map[string]interface{}) (output map[string]interface{}) { 123 | size := len(maps) 124 | if size == 0 { 125 | return output 126 | } 127 | if size == 1 { 128 | return maps[0] 129 | } 130 | output = make(map[string]interface{}) 131 | for _, m := range maps { 132 | for k, v := range m { 133 | output[k] = v 134 | } 135 | } 136 | return output 137 | } 138 | 139 | // SelectFunc - select map keys that yield true either by key or value 140 | func SelectFunc(f func(key string, value interface{}) bool, input map[string]interface{}) (output map[string]interface{}) { 141 | size := len(input) 142 | if size == 0 || f == nil { 143 | return input 144 | } 145 | output = make(map[string]interface{}) 146 | for k, v := range input { 147 | if f(k, v) { 148 | output[k] = v 149 | } 150 | } 151 | return output 152 | } 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mapop 2 | 3 | Regular map[string]interface{} operations. Ruby enumerable inspired package. 4 | 5 | [![Build Status](https://travis-ci.org/linkosmos/mapop.svg?branch=master)](https://travis-ci.org/linkosmos/mapop) 6 | [![Coverage Status](https://coveralls.io/repos/github/linkosmos/mapop/badge.svg?branch=master)](https://coveralls.io/github/linkosmos/mapop?branch=master) 7 | [![GoDoc](http://godoc.org/github.com/linkosmos/mapop?status.svg)](http://godoc.org/github.com/linkosmos/mapop) 8 | [![Go Report Card](http://goreportcard.com/badge/linkosmos/mapop)](http://goreportcard.com/report/linkosmos/mapop) 9 | [![BSD License](http://img.shields.io/badge/license-BSD-blue.svg)](http://opensource.org/licenses/BSD-3-Clause) 10 | 11 | ### Methods 12 | - Keys(input map[string]interface{}) (keys []string) 13 | - Reject(input map[string]interface{}, keys ...string) map[string]interface{} 14 | - Select(input map[string]interface{}, keys ...string) map[string]interface{} 15 | - Split(input map[string]interface{}) (keys []string, values []interface{}) 16 | - Values(input map[string]interface{}) (values []interface{}) 17 | - MapKeys(f func(string) string, input map[string]interface{}) (output map[string]interface{}) 18 | - MapValues(f func(interface{}) interface{}, input map[string]interface{}) (output map[string]interface{}) 19 | - Partition(f func(string, interface{}) bool, input map[string]interface{}) (partition []map[string]interface{}) 20 | - Map(f func(key string, value interface{}) (string, interface{}), input map[string]interface{}) (output map[string]interface{}) 21 | - Collect(input map[string]interface{}) (output map[string]interface{}) 22 | - Merge(maps ...map[string]interface{}) (output map[string]interface{}) 23 | - SelectFunc(f func(key string, value interface{}) bool, input map[string]interface{}) (output map[string]interface{}) 24 | 25 | 26 | ### Usage 27 | 28 | ```go 29 | input := map[string]interface{}{ 30 | "Key1": 2, 31 | "key3": nil, 32 | "val": 2, 33 | "val2": "str", 34 | "val3": 4, 35 | } 36 | ``` 37 | 38 | #### Keys 39 | 40 | ```go 41 | keys := mapop.Keys(input) 42 | 43 | > keys["Key1", "key3", "val", "val2", "val3"] 44 | 45 | ``` 46 | 47 | #### Reject 48 | 49 | ```go 50 | input = mapop.Reject(input, "val", "val2", "val3") 51 | 52 | > input{"Key1": 2, "key3": nil} 53 | ``` 54 | 55 | #### Select 56 | 57 | ```go 58 | input = mapop.Select(input, "val", "val2", "val3") 59 | 60 | > input{"val": 2, "val2": "str", "val3": 4} 61 | 62 | ``` 63 | 64 | #### Split 65 | 66 | ```go 67 | keys, values := mapop.Split(input, "val", "val2", "val3") 68 | 69 | > keys["Key1", "key3", "val", "val2", "val3"] 70 | > values[2,nil,2,"str",4] 71 | 72 | ``` 73 | 74 | #### Values 75 | 76 | ```go 77 | values := mapop.Values(input) 78 | 79 | > values[2,nil,2,"str",4] 80 | 81 | ``` 82 | 83 | #### MapKeys 84 | 85 | ```go 86 | input = mapop.MapKeys(strins.ToUpper, input) 87 | 88 | > input{"KEY1": 2, "KEY3": nil, "VAL": 2, "VAL2": "str", "VAL3": 4} 89 | 90 | ``` 91 | 92 | #### MapValues 93 | 94 | ```go 95 | input = mapop.MapValues(func(val interface{}) interface{} { 96 | return "-10" 97 | }, input) 98 | 99 | > input{"Key1": -10, "key3": -10, "val": -10, "val2": -10, "val3": -10} 100 | 101 | ``` 102 | 103 | #### Partition 104 | 105 | ```go 106 | partitioned := mapop.Partition(func(key string, value interface{}) bool { 107 | return strings.Contains(key, "val") 108 | }, input) 109 | 110 | > partitioned[0]{"Key1": 2, "key3": nil} 111 | > partitioned[1]{"val": 2, "val2": "str", "val3": 4} 112 | ``` 113 | 114 | #### Map 115 | 116 | ```go 117 | input = mapop.Map(func(key string, value interface{}) (string, interface{}) { 118 | if strings.Contains(key, "val") { 119 | return key, key 120 | } else { 121 | return key, value 122 | } 123 | }, input) 124 | 125 | > input{"Key1": 2, "key3": nil, "val": "val", "val2": "val2", "val3": "val3"} 126 | ``` 127 | 128 | #### Collect 129 | 130 | ```go 131 | input = mapop.Collect(input) 132 | 133 | > input{"Key1": 2, "val": 2, "val2": "str", "val3": 4} 134 | ``` 135 | 136 | #### Merge 137 | 138 | ```go 139 | input2 := map[string]interface{}{ 140 | "a2": "str", 141 | "a3": 4, 142 | } 143 | 144 | input = mapop.Merge(input, input2) 145 | 146 | > input{"Key1": 2, "key3": nil, "val": 2, "val2": "str", "val3": 4, "a2": "str", "a3": 4} 147 | ``` 148 | 149 | #### SelectFunc 150 | 151 | ```go 152 | input = mapop.SelectFunc(func(key string, value interface{}) bool { 153 | return key == "val" 154 | }, input) 155 | 156 | > input{"val": 2} 157 | 158 | ``` 159 | 160 | ### License 161 | 162 | Copyright (c) 2015, linkosmos 163 | All rights reserved. 164 | 165 | Redistribution and use in source and binary forms, with or without 166 | modification, are permitted provided that the following conditions are met: 167 | 168 | * Redistributions of source code must retain the above copyright notice, this 169 | list of conditions and the following disclaimer. 170 | 171 | * Redistributions in binary form must reproduce the above copyright notice, 172 | this list of conditions and the following disclaimer in the documentation 173 | and/or other materials provided with the distribution. 174 | 175 | * Neither the name of mapop nor the names of its 176 | contributors may be used to endorse or promote products derived from 177 | this software without specific prior written permission. 178 | 179 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 180 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 182 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 183 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 184 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 185 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 186 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 187 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 188 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 189 | -------------------------------------------------------------------------------- /mapop_test.go: -------------------------------------------------------------------------------- 1 | package mapop 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var splitTests = []struct { 11 | input map[string]interface{} 12 | expectedKeys []string 13 | expectedValues []interface{} 14 | }{ 15 | { 16 | input: map[string]interface{}{ 17 | "key1": 2, 18 | "key3": 2, 19 | }, 20 | expectedKeys: []string{"key1", "key3"}, 21 | expectedValues: []interface{}{2, 2}, 22 | }, 23 | { 24 | input: map[string]interface{}{ 25 | "key1": 1, 26 | "key2": 2, 27 | "key3": 292929, 28 | "key4": 4, 29 | "key5": nil, 30 | }, 31 | expectedKeys: []string{"key1", "key2", "key3", "key4", "key5"}, 32 | expectedValues: []interface{}{1, 2, 292929, 4, nil}, 33 | }, 34 | } 35 | 36 | func TestSplit(t *testing.T) { 37 | for _, test := range splitTests { 38 | keysGot, valuesGot := Split(test.input) 39 | 40 | // Assert size 41 | assert.Equal(t, len(keysGot), len(valuesGot)) 42 | 43 | // Assert keys maps to values 44 | assert.Len(t, keysGot, len(test.input)) 45 | assert.Len(t, valuesGot, len(test.input)) 46 | 47 | for _, keyGot := range keysGot { 48 | assert.Contains(t, test.expectedKeys, keyGot) 49 | } 50 | 51 | for _, valueGot := range valuesGot { 52 | assert.Contains(t, test.expectedValues, valueGot) 53 | } 54 | 55 | // Assert order mapped is correct 56 | for keyGotIndex, keyGot := range keysGot { 57 | inputValue, ok := test.input[keyGot] 58 | assert.True(t, ok) 59 | 60 | gotValue := valuesGot[keyGotIndex] 61 | assert.Equal(t, inputValue, gotValue) 62 | } 63 | } 64 | } 65 | 66 | var selectTests = []struct { 67 | input map[string]interface{} 68 | selectedKeys []string 69 | expectedKeys []string 70 | }{ 71 | { 72 | input: map[string]interface{}{ 73 | "key1": 2, 74 | "key3": 2, 75 | }, 76 | selectedKeys: []string{"key1", "key3"}, 77 | expectedKeys: []string{"key1", "key3"}, 78 | }, 79 | { 80 | input: map[string]interface{}{ 81 | "key1": 1, 82 | "key2": 2, 83 | "key3": 292929, 84 | "key4": 4, 85 | "key5": nil, 86 | }, 87 | selectedKeys: []string{"key1", "key5"}, 88 | expectedKeys: []string{"key1", "key5"}, 89 | }, 90 | { 91 | input: map[string]interface{}{ 92 | "key1": 2, 93 | "key3": 2, 94 | }, 95 | selectedKeys: []string{}, 96 | expectedKeys: []string{"key1", "key3"}, // If select empty return same input 97 | }, 98 | { 99 | input: map[string]interface{}{ 100 | "key1": 2, 101 | "key3": 2, 102 | }, 103 | selectedKeys: []string{"noKey"}, 104 | expectedKeys: []string{}, 105 | }, 106 | { 107 | input: map[string]interface{}{ 108 | "key1": 2, 109 | "key3": 2, 110 | }, 111 | selectedKeys: []string{"noKey", "no", "nokey2", "nokey3"}, 112 | expectedKeys: []string{}, 113 | }, 114 | { 115 | input: map[string]interface{}{}, 116 | selectedKeys: []string{"noKey", "no", "nokey2", "nokey3"}, 117 | expectedKeys: []string{}, 118 | }, 119 | { 120 | input: map[string]interface{}{}, 121 | selectedKeys: []string{}, 122 | expectedKeys: []string{}, 123 | }, 124 | } 125 | 126 | func TestSelect(t *testing.T) { 127 | for _, test := range selectTests { 128 | got := Select(test.input, test.selectedKeys...) 129 | keysGot, _ := Split(got) 130 | 131 | assert.Equal(t, len(keysGot), len(test.expectedKeys)) 132 | 133 | for _, keyGot := range keysGot { 134 | assert.Contains(t, test.expectedKeys, keyGot) 135 | } 136 | } 137 | } 138 | 139 | var rejectTests = []struct { 140 | input map[string]interface{} 141 | rejectedKeys []string 142 | expectedKeys []string 143 | }{ 144 | { 145 | input: map[string]interface{}{ 146 | "key1": 2, 147 | "key3": 2, 148 | }, 149 | rejectedKeys: []string{"key3"}, 150 | expectedKeys: []string{"key1"}, 151 | }, 152 | { 153 | input: map[string]interface{}{ 154 | "key1": 1, 155 | "key2": 2, 156 | "key3": 292929, 157 | "key4": 4, 158 | "key5": nil, 159 | }, 160 | rejectedKeys: []string{"key5"}, 161 | expectedKeys: []string{"key1", "key2", "key3", "key4"}, 162 | }, 163 | { 164 | input: map[string]interface{}{ 165 | "key1": 2, 166 | "key3": 2, 167 | }, 168 | rejectedKeys: []string{}, 169 | expectedKeys: []string{"key1", "key3"}, // If reject empty return same input 170 | }, 171 | { 172 | input: map[string]interface{}{ 173 | "k3": 2, 174 | "k1": 2, 175 | }, 176 | rejectedKeys: []string{"noKey"}, 177 | expectedKeys: []string{"k1", "k3"}, 178 | }, 179 | { 180 | input: map[string]interface{}{ 181 | "key1": 2, 182 | "key3": 2, 183 | }, 184 | rejectedKeys: []string{"noKey", "no", "nokey2", "nokey3"}, 185 | expectedKeys: []string{"key1", "key3"}, 186 | }, 187 | { 188 | input: map[string]interface{}{}, 189 | rejectedKeys: []string{"noKey", "no", "nokey2", "nokey3"}, 190 | expectedKeys: []string{}, 191 | }, 192 | { 193 | input: map[string]interface{}{}, 194 | rejectedKeys: []string{}, 195 | expectedKeys: []string{}, 196 | }, 197 | } 198 | 199 | func TestReject(t *testing.T) { 200 | for _, test := range rejectTests { 201 | got := Reject(test.input, test.rejectedKeys...) 202 | keysGot, _ := Split(got) 203 | 204 | assert.Equal(t, len(keysGot), len(test.expectedKeys)) 205 | 206 | for _, keyGot := range keysGot { 207 | assert.Contains(t, test.expectedKeys, keyGot) 208 | } 209 | } 210 | } 211 | 212 | var mapKeysTests = []struct { 213 | input map[string]interface{} 214 | expected map[string]interface{} 215 | }{ 216 | { 217 | input: map[string]interface{}{ 218 | "key1": 2, 219 | "KEY3": "aw", 220 | "NIL": nil, 221 | }, 222 | expected: map[string]interface{}{ 223 | "key1": 2, 224 | "key3": "aw", 225 | "nil": nil, 226 | }, 227 | }, 228 | } 229 | 230 | func TestMapKeys(t *testing.T) { 231 | for _, test := range mapKeysTests { 232 | got := MapKeys(strings.ToLower, test.input) 233 | 234 | assert.NotNil(t, got) 235 | for expectedKey, expectedValue := range test.expected { 236 | valueGot := got[expectedKey] 237 | 238 | assert.Equal(t, expectedValue, valueGot) 239 | } 240 | } 241 | } 242 | 243 | var mapValuesTests = []struct { 244 | input map[string]interface{} 245 | }{ 246 | { 247 | input: map[string]interface{}{ 248 | "key1": 2, 249 | "key3": "aw", 250 | "nil": nil, 251 | }, 252 | }, 253 | } 254 | 255 | func TestMapValues(t *testing.T) { 256 | expectedValue := "1" 257 | f := func(input interface{}) interface{} { 258 | return expectedValue 259 | } 260 | 261 | for _, test := range mapValuesTests { 262 | got := MapValues(f, test.input) 263 | 264 | assert.NotNil(t, got) 265 | for _, gotValue := range got { 266 | assert.Equal(t, expectedValue, gotValue) 267 | } 268 | } 269 | } 270 | 271 | var partitionByKeyTests = []struct { 272 | input map[string]interface{} 273 | expectedPartition1 map[string]interface{} 274 | expectedPartition2 map[string]interface{} 275 | partitionFunc func(string, interface{}) bool 276 | }{ 277 | { 278 | input: nil, 279 | expectedPartition1: nil, 280 | expectedPartition2: nil, 281 | partitionFunc: func(s string, i interface{}) bool { 282 | return true 283 | }, 284 | }, 285 | { 286 | input: map[string]interface{}{}, 287 | expectedPartition1: map[string]interface{}{}, 288 | expectedPartition2: nil, 289 | partitionFunc: func(s string, i interface{}) bool { 290 | return true 291 | }, 292 | }, 293 | { 294 | input: map[string]interface{}{ 295 | "key1": 2, 296 | "key2": 3, 297 | "name": nil, 298 | "surname": nil, 299 | }, 300 | expectedPartition1: map[string]interface{}{ 301 | "key1": 2, 302 | "key2": 3, 303 | }, 304 | expectedPartition2: map[string]interface{}{ 305 | "name": nil, 306 | "surname": nil, 307 | }, 308 | partitionFunc: func(s string, i interface{}) bool { 309 | return strings.Contains(s, "key") 310 | }, 311 | }, 312 | { 313 | input: map[string]interface{}{ 314 | "key1": 2, 315 | "key2": 3, 316 | "name": nil, 317 | "surname": nil, 318 | }, 319 | expectedPartition1: map[string]interface{}{ 320 | "key1": 2, 321 | "key2": 3, 322 | "name": nil, 323 | "surname": nil, 324 | }, 325 | expectedPartition2: map[string]interface{}{}, 326 | partitionFunc: func(s string, i interface{}) bool { 327 | return true 328 | }, 329 | }, 330 | { 331 | input: map[string]interface{}{ 332 | "key1": 2, 333 | "key2": 3, 334 | "name": nil, 335 | "surname": nil, 336 | }, 337 | expectedPartition1: map[string]interface{}{}, 338 | expectedPartition2: map[string]interface{}{ 339 | "key1": 2, 340 | "key2": 3, 341 | "name": nil, 342 | "surname": nil, 343 | }, 344 | partitionFunc: func(s string, i interface{}) bool { 345 | return false 346 | }, 347 | }, 348 | } 349 | 350 | func TestPartition(t *testing.T) { 351 | for _, test := range partitionByKeyTests { 352 | got := Partition(test.partitionFunc, test.input) 353 | 354 | assert.Equal(t, test.expectedPartition1, got[0]) 355 | assert.Equal(t, test.expectedPartition2, got[1]) 356 | } 357 | } 358 | 359 | var mapTests = []struct { 360 | input map[string]interface{} 361 | expected map[string]interface{} 362 | mapFunc func(string, interface{}) (string, interface{}) 363 | }{ 364 | { 365 | input: map[string]interface{}{ 366 | "key1": 2, 367 | "KeY3": "aw", 368 | "NIL": nil, 369 | }, 370 | expected: map[string]interface{}{ 371 | "KEY1": "CHANGED", 372 | "KEY3": "CHANGED", 373 | "NIL": "CHANGED", 374 | }, 375 | mapFunc: func(k string, v interface{}) (string, interface{}) { 376 | return strings.ToUpper(k), "CHANGED" 377 | }, 378 | }, 379 | } 380 | 381 | func TestMap(t *testing.T) { 382 | for _, test := range mapTests { 383 | got := Map(test.mapFunc, test.input) 384 | 385 | assert.NotNil(t, got) 386 | for expectedKey, expectedValue := range test.expected { 387 | valueGot := got[expectedKey] 388 | 389 | assert.Equal(t, expectedValue, valueGot) 390 | } 391 | } 392 | } 393 | 394 | var collectTests = []struct { 395 | input map[string]interface{} 396 | expected map[string]interface{} 397 | }{ 398 | { 399 | input: map[string]interface{}{ 400 | "key1": 2, 401 | "KeY3": "aw", 402 | "NIL": nil, 403 | }, 404 | expected: map[string]interface{}{ 405 | "key1": 2, 406 | "KeY3": "aw", 407 | }, 408 | }, 409 | { 410 | input: map[string]interface{}{ 411 | "key1": 0, 412 | "KeY3": "", 413 | }, 414 | expected: map[string]interface{}{ 415 | "key1": 0, 416 | "KeY3": "", 417 | }, 418 | }, 419 | { 420 | input: map[string]interface{}{}, 421 | expected: map[string]interface{}{}, 422 | }, 423 | } 424 | 425 | func TestCollect(t *testing.T) { 426 | for _, test := range collectTests { 427 | got := Collect(test.input) 428 | 429 | assert.Equal(t, test.expected, got) 430 | } 431 | } 432 | 433 | var mergeTests = []struct { 434 | input1 map[string]interface{} 435 | input2 map[string]interface{} 436 | input3 map[string]interface{} 437 | expected map[string]interface{} 438 | }{ 439 | { 440 | input1: map[string]interface{}{ 441 | "key1": 2, 442 | }, 443 | input2: map[string]interface{}{ 444 | "key1": "2", 445 | }, 446 | input3: map[string]interface{}{ 447 | "KeY3": "aw", 448 | }, 449 | expected: map[string]interface{}{ 450 | "key1": "2", 451 | "KeY3": "aw", 452 | }, 453 | }, 454 | { 455 | input1: map[string]interface{}{}, 456 | input2: nil, 457 | input3: map[string]interface{}{ 458 | "KeY3": "aw", 459 | }, 460 | expected: map[string]interface{}{ 461 | "KeY3": "aw", 462 | }, 463 | }, 464 | { 465 | input1: nil, 466 | input2: nil, 467 | input3: nil, 468 | expected: map[string]interface{}{}, 469 | }, 470 | } 471 | 472 | func TestMerge(t *testing.T) { 473 | for _, test := range mergeTests { 474 | got := Merge(test.input1, test.input2, test.input3) 475 | 476 | assert.Equal(t, test.expected, got) 477 | } 478 | } 479 | 480 | var selectFuncTests = []struct { 481 | input map[string]interface{} 482 | f func(string, interface{}) bool 483 | expected map[string]interface{} 484 | }{ 485 | { 486 | input: map[string]interface{}{ 487 | "key1": "1", 488 | "key2": 2, 489 | "val1": 1, 490 | "val2": 2, 491 | }, 492 | f: func(k string, v interface{}) bool { 493 | return strings.Contains(k, "key") 494 | }, 495 | expected: map[string]interface{}{ 496 | "key1": "1", 497 | "key2": 2, 498 | }, 499 | }, 500 | { 501 | input: map[string]interface{}{ 502 | "key1": "1", 503 | "key2": 2, 504 | "val1": 1, 505 | "val2": 2, 506 | }, 507 | f: nil, 508 | expected: map[string]interface{}{ 509 | "key1": "1", 510 | "key2": 2, 511 | "val1": 1, 512 | "val2": 2, 513 | }, 514 | }, 515 | { 516 | input: nil, 517 | f: func(k string, v interface{}) bool { 518 | return strings.Contains(k, "key") 519 | }, 520 | expected: nil, 521 | }, 522 | } 523 | 524 | func TestSelectFunc(t *testing.T) { 525 | for _, test := range selectFuncTests { 526 | got := SelectFunc(test.f, test.input) 527 | 528 | assert.Equal(t, test.expected, got) 529 | } 530 | } 531 | --------------------------------------------------------------------------------