github.com/sacloud/iaas-api-go@v1.12.0/mapconv/map_test.go (about) 1 // Copyright 2022-2023 The sacloud/iaas-api-go Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mapconv 16 17 import ( 18 "testing" 19 20 "github.com/fatih/structs" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestMap_Set(t *testing.T) { 25 expects := []struct { 26 caseName string 27 source map[string]interface{} 28 dest map[string]interface{} 29 }{ 30 { 31 caseName: "minimum", 32 source: map[string]interface{}{ 33 "test": "test", 34 }, 35 dest: map[string]interface{}{ 36 "test": "test", 37 }, 38 }, 39 { 40 caseName: "nested", 41 source: map[string]interface{}{ 42 "test.A": "A", 43 "test.B": "B", 44 "test.C.C1": "C1", 45 "test.C.C2": "C2", 46 "outer": "outer", 47 "int": 1, 48 "float": 1.1, 49 }, 50 dest: map[string]interface{}{ 51 "test": map[string]interface{}{ 52 "A": "A", 53 "B": "B", 54 "C": map[string]interface{}{ 55 "C1": "C1", 56 "C2": "C2", 57 }, 58 }, 59 "outer": "outer", 60 "int": 1, 61 "float": 1.1, 62 }, 63 }, 64 { 65 caseName: "slice", 66 source: map[string]interface{}{ 67 "slice.slice.value": []interface{}{"value4", "value5"}, 68 }, 69 dest: map[string]interface{}{ 70 "slice": map[string]interface{}{ 71 "slice": map[string]interface{}{ 72 "value": []interface{}{"value4", "value5"}, 73 }, 74 }, 75 }, 76 }, 77 { 78 caseName: "expanded slice", 79 source: map[string]interface{}{ 80 "[]slice.value": []interface{}{"value1", "value2"}, 81 }, 82 dest: map[string]interface{}{ 83 "slice": []map[string]interface{}{ 84 {"value": "value1"}, 85 {"value": "value2"}, 86 }, 87 }, 88 }, 89 { 90 caseName: "expanded nested slice", 91 source: map[string]interface{}{ 92 "[]slice.slice.value": []interface{}{"value4", "value5"}, 93 }, 94 dest: map[string]interface{}{ 95 "slice": []map[string]interface{}{ 96 { 97 "slice": map[string]interface{}{ 98 "value": "value4", 99 }, 100 }, 101 { 102 "slice": map[string]interface{}{ 103 "value": "value5", 104 }, 105 }, 106 }, 107 }, 108 }, 109 { 110 caseName: "expanded nested slice with middle slice", 111 source: map[string]interface{}{ 112 "slice.[]slice.value": []interface{}{"value4", "value5"}, 113 }, 114 dest: map[string]interface{}{ 115 "slice": map[string]interface{}{ 116 "slice": []map[string]interface{}{ 117 {"value": "value4"}, 118 {"value": "value5"}, 119 }, 120 }, 121 }, 122 }, 123 { 124 caseName: "expanded nested slice with last slice", 125 source: map[string]interface{}{ 126 "slice.slice.[]value": []interface{}{"value4", "value5"}, 127 }, 128 dest: map[string]interface{}{ 129 "slice": map[string]interface{}{ 130 "slice": map[string]interface{}{ 131 "value": []interface{}{"value4", "value5"}, 132 }, 133 }, 134 }, 135 }, 136 { 137 caseName: "expanded deep nested slice", 138 source: map[string]interface{}{ 139 "[]slice.[]slice.value": []interface{}{"value4", "value5"}, 140 }, 141 dest: map[string]interface{}{ 142 "slice": []map[string]interface{}{ 143 { 144 "slice": []map[string]interface{}{ 145 {"value": "value4"}, 146 }, 147 }, 148 { 149 "slice": []map[string]interface{}{ 150 {"value": "value5"}, 151 }, 152 }, 153 }, 154 }, 155 }, 156 } 157 158 for _, expect := range expects { 159 t.Run(expect.caseName, func(t *testing.T) { 160 m := Map(make(map[string]interface{})) 161 for k, v := range expect.source { 162 m.Set(k, v) 163 } 164 require.Equal(t, expect.dest, m.Map()) 165 }) 166 } 167 } 168 169 func TestMap_Get(t *testing.T) { 170 expects := []struct { 171 caseName string 172 keyValues map[string]interface{} 173 source map[string]interface{} 174 err error 175 }{ 176 { 177 caseName: "minimum", 178 keyValues: map[string]interface{}{ 179 "test": "test", 180 }, 181 source: map[string]interface{}{ 182 "test": "test", 183 }, 184 }, 185 { 186 caseName: "nested", 187 keyValues: map[string]interface{}{ 188 "test.A": "A", 189 "test.B": "B", 190 "test.C.C1": "C1", 191 "test.C.C2": "C2", 192 "outer": "outer", 193 "int": 1, 194 "float": 1.1, 195 }, 196 source: map[string]interface{}{ 197 "test": map[string]interface{}{ 198 "A": "A", 199 "B": "B", 200 "C": map[string]interface{}{ 201 "C1": "C1", 202 "C2": "C2", 203 }, 204 }, 205 "outer": "outer", 206 "int": 1, 207 "float": 1.1, 208 }, 209 }, 210 { 211 caseName: "slice", 212 keyValues: map[string]interface{}{ 213 "slice.value": []interface{}{"value1", "value2"}, 214 }, 215 source: map[string]interface{}{ 216 "slice": []map[string]interface{}{ 217 {"value": "value1"}, 218 {"value": "value2"}, 219 }, 220 }, 221 }, 222 { 223 caseName: "nested slice", 224 keyValues: map[string]interface{}{ 225 "slice.slice.value": []interface{}{"value4", "value5"}, 226 }, 227 source: map[string]interface{}{ 228 "slice": []map[string]interface{}{ 229 {"value": "value1"}, 230 {"value": "value2"}, 231 { 232 "value": "value3", 233 "slice": []map[string]interface{}{ 234 {"value": "value4"}, 235 {"value": "value5"}, 236 }, 237 }, 238 }, 239 }, 240 }, 241 { 242 caseName: "with invalid key", 243 keyValues: map[string]interface{}{ 244 "test.A.B": nil, 245 }, 246 source: map[string]interface{}{ 247 "test": map[string]interface{}{ 248 "A": "test", 249 }, 250 }, 251 }, 252 } 253 254 for _, expect := range expects { 255 t.Run(expect.caseName, func(t *testing.T) { 256 m := Map(expect.source) 257 for k, v := range expect.keyValues { 258 value, err := m.Get(k) 259 require.Equal(t, expect.err, err) 260 if err == nil { 261 require.Equal(t, v, value) 262 } 263 } 264 }) 265 } 266 } 267 268 type A struct { 269 Foo *B `structs:",omitempty"` 270 } 271 272 type B struct { 273 Bar *C `structs:",omitempty"` 274 } 275 276 type C struct { 277 Baz interface{} `structs:",omitempty"` 278 } 279 280 func TestMap_GetWithEmptyStruct(t *testing.T) { 281 cases := []struct { 282 in interface{} 283 expect interface{} 284 }{ 285 {in: &A{Foo: &B{Bar: &C{Baz: "FooBarBaz"}}}, expect: "FooBarBaz"}, 286 {in: &A{Foo: &B{Bar: &C{}}}, expect: nil}, 287 {in: &A{Foo: &B{}}, expect: nil}, 288 } 289 for _, tc := range cases { 290 m := Map(structs.Map(tc.in)) 291 got, err := m.Get("Foo.Bar.Baz") 292 if err != nil { 293 t.Fatal(err) 294 } 295 if got != tc.expect { 296 t.Fatalf("got unexpected value: expected: %v actual:%v", tc.expect, got) 297 } 298 } 299 }