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  }