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