github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/tpl/collections/merge_test.go (about) 1 // Copyright 2019 The Hugo Authors. All rights reserved. 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 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package collections 15 16 import ( 17 "bytes" 18 "reflect" 19 "testing" 20 21 "github.com/gohugoio/hugo/common/maps" 22 "github.com/gohugoio/hugo/deps" 23 "github.com/gohugoio/hugo/parser" 24 "github.com/gohugoio/hugo/parser/metadecoders" 25 26 qt "github.com/frankban/quicktest" 27 ) 28 29 func TestMerge(t *testing.T) { 30 ns := New(&deps.Deps{}) 31 32 simpleMap := map[string]interface{}{"a": 1, "b": 2} 33 34 for i, test := range []struct { 35 name string 36 params []interface{} 37 expect interface{} 38 isErr bool 39 }{ 40 { 41 "basic", 42 []interface{}{ 43 map[string]interface{}{"a": 42, "c": 3}, 44 map[string]interface{}{"a": 1, "b": 2}, 45 }, 46 map[string]interface{}{"a": 1, "b": 2, "c": 3}, 47 false, 48 }, 49 { 50 "multi", 51 []interface{}{ 52 map[string]interface{}{"a": 42, "c": 3, "e": 11}, 53 map[string]interface{}{"a": 1, "b": 2}, 54 map[string]interface{}{"a": 9, "c": 4, "d": 7}, 55 }, 56 map[string]interface{}{"a": 9, "b": 2, "c": 4, "d": 7, "e": 11}, 57 false, 58 }, 59 { 60 "basic case insensitive", 61 []interface{}{ 62 map[string]interface{}{"A": 42, "c": 3}, 63 map[string]interface{}{"a": 1, "b": 2}, 64 }, 65 map[string]interface{}{"a": 1, "b": 2, "c": 3}, 66 false, 67 }, 68 { 69 "nested", 70 []interface{}{ 71 map[string]interface{}{"a": 42, "c": 3, "b": map[string]interface{}{"d": 55, "e": 66, "f": 3}}, 72 map[string]interface{}{"a": 1, "b": map[string]interface{}{"d": 1, "e": 2}}, 73 }, 74 map[string]interface{}{"a": 1, "b": map[string]interface{}{"d": 1, "e": 2, "f": 3}, "c": 3}, 75 false, 76 }, 77 { 78 // https://github.com/gohugoio/hugo/issues/6633 79 "params dst", 80 []interface{}{ 81 map[string]interface{}{"a": 42, "c": 3}, 82 maps.Params{"a": 1, "b": 2}, 83 }, 84 maps.Params{"a": int(1), "b": int(2), "c": int(3)}, 85 false, 86 }, 87 { 88 "params dst, upper case src", 89 []interface{}{ 90 map[string]interface{}{"a": 42, "C": 3}, 91 maps.Params{"a": 1, "b": 2}, 92 }, 93 maps.Params{"a": int(1), "b": int(2), "c": int(3)}, 94 false, 95 }, 96 { 97 "params src", 98 []interface{}{ 99 maps.Params{"a": 42, "c": 3}, 100 map[string]interface{}{"a": 1, "c": 2}, 101 }, 102 map[string]interface{}{"a": int(1), "c": int(2)}, 103 false, 104 }, 105 { 106 "params src, upper case dst", 107 []interface{}{ 108 maps.Params{"a": 42, "c": 3}, 109 map[string]interface{}{"a": 1, "C": 2}, 110 }, 111 map[string]interface{}{"a": int(1), "C": int(2)}, 112 false, 113 }, 114 { 115 "nested, params dst", 116 []interface{}{ 117 map[string]interface{}{"a": 42, "c": 3, "b": map[string]interface{}{"d": 55, "e": 66, "f": 3}}, 118 maps.Params{"a": 1, "b": maps.Params{"d": 1, "e": 2}}, 119 }, 120 maps.Params{"a": 1, "b": maps.Params{"d": 1, "e": 2, "f": 3}, "c": 3}, 121 false, 122 }, 123 { 124 // https://github.com/gohugoio/hugo/issues/7899 125 "matching keys with non-map src value", 126 []interface{}{ 127 map[string]interface{}{"k": "v"}, 128 map[string]interface{}{"k": map[string]interface{}{"k2": "v2"}}, 129 }, 130 map[string]interface{}{"k": map[string]interface{}{"k2": "v2"}}, 131 false, 132 }, 133 {"src nil", []interface{}{nil, simpleMap}, simpleMap, false}, 134 // Error cases. 135 {"dst not a map", []interface{}{nil, "not a map"}, nil, true}, 136 {"src not a map", []interface{}{"not a map", simpleMap}, nil, true}, 137 {"different map types", []interface{}{map[int]interface{}{32: "a"}, simpleMap}, nil, true}, 138 {"all nil", []interface{}{nil, nil}, nil, true}, 139 } { 140 141 test := test 142 143 t.Run(test.name, func(t *testing.T) { 144 t.Parallel() 145 errMsg := qt.Commentf("[%d] %v", i, test) 146 147 c := qt.New(t) 148 149 result, err := ns.Merge(test.params...) 150 151 if test.isErr { 152 c.Assert(err, qt.Not(qt.IsNil), errMsg) 153 return 154 } 155 156 c.Assert(err, qt.IsNil) 157 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 158 }) 159 } 160 } 161 162 func TestMergeDataFormats(t *testing.T) { 163 c := qt.New(t) 164 ns := New(&deps.Deps{}) 165 166 toml1 := ` 167 V1 = "v1_1" 168 169 [V2s] 170 V21 = "v21_1" 171 172 ` 173 174 toml2 := ` 175 V1 = "v1_2" 176 V2 = "v2_2" 177 178 [V2s] 179 V21 = "v21_2" 180 V22 = "v22_2" 181 182 ` 183 184 meta1, err := metadecoders.Default.UnmarshalToMap([]byte(toml1), metadecoders.TOML) 185 c.Assert(err, qt.IsNil) 186 meta2, err := metadecoders.Default.UnmarshalToMap([]byte(toml2), metadecoders.TOML) 187 c.Assert(err, qt.IsNil) 188 189 for _, format := range []metadecoders.Format{metadecoders.JSON, metadecoders.YAML, metadecoders.TOML} { 190 191 var dataStr1, dataStr2 bytes.Buffer 192 err = parser.InterfaceToConfig(meta1, format, &dataStr1) 193 c.Assert(err, qt.IsNil) 194 err = parser.InterfaceToConfig(meta2, format, &dataStr2) 195 c.Assert(err, qt.IsNil) 196 197 dst, err := metadecoders.Default.UnmarshalToMap(dataStr1.Bytes(), format) 198 c.Assert(err, qt.IsNil) 199 src, err := metadecoders.Default.UnmarshalToMap(dataStr2.Bytes(), format) 200 c.Assert(err, qt.IsNil) 201 202 merged, err := ns.Merge(src, dst) 203 c.Assert(err, qt.IsNil) 204 205 c.Assert( 206 merged, 207 qt.DeepEquals, 208 map[string]interface{}{ 209 "V1": "v1_1", "V2": "v2_2", 210 "V2s": map[string]interface{}{"V21": "v21_1", "V22": "v22_2"}, 211 }) 212 } 213 } 214 215 func TestCaseInsensitiveMapLookup(t *testing.T) { 216 c := qt.New(t) 217 218 m1 := reflect.ValueOf(map[string]interface{}{ 219 "a": 1, 220 "B": 2, 221 }) 222 223 m2 := reflect.ValueOf(map[int]interface{}{ 224 1: 1, 225 2: 2, 226 }) 227 228 var found bool 229 230 a, found := caseInsensitiveLookup(m1, reflect.ValueOf("A")) 231 c.Assert(found, qt.Equals, true) 232 c.Assert(a.Interface(), qt.Equals, 1) 233 234 b, found := caseInsensitiveLookup(m1, reflect.ValueOf("b")) 235 c.Assert(found, qt.Equals, true) 236 c.Assert(b.Interface(), qt.Equals, 2) 237 238 two, found := caseInsensitiveLookup(m2, reflect.ValueOf(2)) 239 c.Assert(found, qt.Equals, true) 240 c.Assert(two.Interface(), qt.Equals, 2) 241 }