github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/coll/coll_test.go (about)

     1  package coll
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestSlice(t *testing.T) {
    12  	expected := []string{"foo", "bar"}
    13  	actual := Slice("foo", "bar")
    14  	assert.Equal(t, expected[0], actual[0])
    15  	assert.Equal(t, expected[1], actual[1])
    16  }
    17  
    18  func TestHas(t *testing.T) {
    19  	in := map[string]interface{}{
    20  		"foo": "bar",
    21  		"baz": map[string]interface{}{
    22  			"qux": "quux",
    23  		},
    24  	}
    25  
    26  	testdata := []struct {
    27  		in  interface{}
    28  		key interface{}
    29  		out bool
    30  	}{
    31  		{in, "foo", true},
    32  		{in, "bar", false},
    33  		{in["baz"], "qux", true},
    34  		{[]string{"foo", "bar", "baz"}, "bar", true},
    35  		{[]interface{}{"foo", "bar", "baz"}, "bar", true},
    36  		{[]interface{}{"foo", "bar", "baz"}, 42, false},
    37  		{[]int{1, 2, 42}, 42, true},
    38  	}
    39  
    40  	for _, d := range testdata {
    41  		assert.Equal(t, d.out, Has(d.in, d.key))
    42  	}
    43  }
    44  
    45  func TestDict(t *testing.T) {
    46  	testdata := []struct {
    47  		expected map[string]interface{}
    48  		args     []interface{}
    49  	}{
    50  		{expected: map[string]interface{}{}},
    51  		{args: []interface{}{}, expected: map[string]interface{}{}},
    52  		{args: []interface{}{"foo"}, expected: map[string]interface{}{"foo": ""}},
    53  		{args: []interface{}{42}, expected: map[string]interface{}{"42": ""}},
    54  		{args: []interface{}{"foo", nil}, expected: map[string]interface{}{"foo": nil}},
    55  		{args: []interface{}{"foo", "bar"}, expected: map[string]interface{}{"foo": "bar"}},
    56  		{args: []interface{}{"foo", "bar", "baz", true}, expected: map[string]interface{}{
    57  			"foo": "bar",
    58  			"baz": true,
    59  		}},
    60  	}
    61  
    62  	for _, d := range testdata {
    63  		actual, _ := Dict(d.args...)
    64  		assert.Equal(t, d.expected, actual)
    65  	}
    66  }
    67  
    68  func TestKeys(t *testing.T) {
    69  	_, err := Keys()
    70  	require.Error(t, err)
    71  
    72  	in := map[string]interface{}{
    73  		"foo": 1,
    74  		"bar": 2,
    75  	}
    76  	expected := []string{"bar", "foo"}
    77  	keys, err := Keys(in)
    78  	require.NoError(t, err)
    79  	assert.EqualValues(t, expected, keys)
    80  
    81  	in2 := map[string]interface{}{
    82  		"baz": 3,
    83  		"qux": 4,
    84  	}
    85  	expected = []string{"bar", "foo", "baz", "qux"}
    86  	keys, err = Keys(in, in2)
    87  	require.NoError(t, err)
    88  	assert.EqualValues(t, expected, keys)
    89  
    90  	in3 := map[string]interface{}{
    91  		"Foo": 5,
    92  		"Bar": 6,
    93  		"foo": 7,
    94  		"bar": 8,
    95  	}
    96  	expected = []string{"bar", "foo", "baz", "qux", "Bar", "Foo", "bar", "foo"}
    97  	keys, err = Keys(in, in2, in3)
    98  	require.NoError(t, err)
    99  	assert.EqualValues(t, expected, keys)
   100  }
   101  
   102  func TestValues(t *testing.T) {
   103  	_, err := Values()
   104  	require.Error(t, err)
   105  
   106  	in := map[string]interface{}{
   107  		"foo": 1,
   108  		"bar": 2,
   109  	}
   110  	expected := []interface{}{2, 1}
   111  	values, err := Values(in)
   112  	require.NoError(t, err)
   113  	assert.EqualValues(t, expected, values)
   114  
   115  	in2 := map[string]interface{}{
   116  		"baz": 3,
   117  		"qux": 4,
   118  	}
   119  	expected = []interface{}{2, 1, 3, 4}
   120  	values, err = Values(in, in2)
   121  	require.NoError(t, err)
   122  	assert.EqualValues(t, expected, values)
   123  
   124  	in3 := map[string]interface{}{
   125  		"Foo": 5,
   126  		"Bar": 6,
   127  		"foo": 7,
   128  		"bar": 8,
   129  	}
   130  	expected = []interface{}{2, 1, 3, 4, 6, 5, 8, 7}
   131  	values, err = Values(in, in2, in3)
   132  	require.NoError(t, err)
   133  	assert.EqualValues(t, expected, values)
   134  }
   135  
   136  func TestAppend(t *testing.T) {
   137  	out, err := Append(42, []interface{}{})
   138  	require.NoError(t, err)
   139  	assert.EqualValues(t, []interface{}{42}, out)
   140  
   141  	out, err = Append(42, []interface{}{4.9, false, "foo"})
   142  	require.NoError(t, err)
   143  	assert.EqualValues(t, []interface{}{4.9, false, "foo", 42}, out)
   144  
   145  	// a strange but valid use-cases, since we're converting to an []interface{}
   146  	out, err = Append(42, []string{"foo"})
   147  	require.NoError(t, err)
   148  	assert.EqualValues(t, []interface{}{"foo", 42}, out)
   149  
   150  	out, err = Append("baz", []string{"foo", "bar"})
   151  	require.NoError(t, err)
   152  	assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out)
   153  }
   154  
   155  func TestPrepend(t *testing.T) {
   156  	out, err := Prepend(42, []interface{}{})
   157  	require.NoError(t, err)
   158  	assert.EqualValues(t, []interface{}{42}, out)
   159  
   160  	out, err = Prepend(42, []interface{}{4.9, false, "foo"})
   161  	require.NoError(t, err)
   162  	assert.EqualValues(t, []interface{}{42, 4.9, false, "foo"}, out)
   163  
   164  	// a strange but valid use-cases, since we're converting to an []interface{}
   165  	out, err = Prepend(42, []string{"foo"})
   166  	require.NoError(t, err)
   167  	assert.EqualValues(t, []interface{}{42, "foo"}, out)
   168  
   169  	out, err = Prepend("foo", []string{"bar", "baz"})
   170  	require.NoError(t, err)
   171  	assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out)
   172  }
   173  
   174  func TestUniq(t *testing.T) {
   175  	out, err := Uniq([]interface{}{1, 2, 3, 1, true, false, true, "1", 2})
   176  	require.NoError(t, err)
   177  	assert.EqualValues(t, []interface{}{1, 2, 3, true, false, "1"}, out)
   178  
   179  	out, err = Uniq([]string{"one", "two", "one", "three"})
   180  	require.NoError(t, err)
   181  	assert.EqualValues(t, []interface{}{"one", "two", "three"}, out)
   182  }
   183  
   184  func TestReverse(t *testing.T) {
   185  	out, err := Reverse([]interface{}{})
   186  	require.NoError(t, err)
   187  	assert.EqualValues(t, []interface{}{}, out)
   188  
   189  	out, err = Reverse([]interface{}{8})
   190  	require.NoError(t, err)
   191  	assert.EqualValues(t, []interface{}{8}, out)
   192  
   193  	out, err = Reverse([]interface{}{1, 2, 3, 4})
   194  	require.NoError(t, err)
   195  	assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out)
   196  
   197  	out, err = Reverse([]int{1, 2, 3, 4})
   198  	require.NoError(t, err)
   199  	assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out)
   200  }
   201  
   202  func TestMerge(t *testing.T) {
   203  	dst := map[string]interface{}{}
   204  	src := map[string]interface{}{}
   205  	expected := map[string]interface{}{}
   206  
   207  	out, err := Merge(dst, src)
   208  	require.NoError(t, err)
   209  	assert.EqualValues(t, expected, out)
   210  
   211  	dst = map[string]interface{}{"a": 4, "c": 5}
   212  	src = map[string]interface{}{"a": 1, "b": 2, "c": 3}
   213  	expected = map[string]interface{}{
   214  		"a": dst["a"], "b": src["b"], "c": dst["c"],
   215  	}
   216  
   217  	out, err = Merge(dst, src)
   218  	require.NoError(t, err)
   219  	assert.EqualValues(t, expected, out)
   220  
   221  	dst = map[string]interface{}{"a": 4, "c": 5}
   222  	src = map[string]interface{}{"a": 1, "b": 2, "c": 3}
   223  	src2 := map[string]interface{}{"a": 1, "b": 2, "c": 3, "d": 4}
   224  	expected = map[string]interface{}{
   225  		"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
   226  	}
   227  
   228  	out, err = Merge(dst, src, src2)
   229  	require.NoError(t, err)
   230  	assert.EqualValues(t, expected, out)
   231  
   232  	dst = map[string]interface{}{"a": false, "c": 5}
   233  	src = map[string]interface{}{"a": true, "b": 2, "c": 3}
   234  	src2 = map[string]interface{}{"a": true, "b": 2, "c": 3, "d": 4}
   235  	expected = map[string]interface{}{
   236  		"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
   237  	}
   238  
   239  	out, err = Merge(dst, src, src2)
   240  	require.NoError(t, err)
   241  	assert.EqualValues(t, expected, out)
   242  
   243  	dst = map[string]interface{}{"a": true, "c": 5}
   244  	src = map[string]interface{}{
   245  		"a": false,
   246  		"b": map[string]interface{}{
   247  			"ca": "foo",
   248  		},
   249  	}
   250  	src2 = map[string]interface{}{"a": false, "b": 2, "c": 3, "d": 4}
   251  	expected = map[string]interface{}{
   252  		"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
   253  	}
   254  
   255  	out, err = Merge(dst, src, src2)
   256  	require.NoError(t, err)
   257  	assert.EqualValues(t, expected, out)
   258  
   259  	dst = map[string]interface{}{
   260  		"a": true,
   261  		"b": map[string]interface{}{
   262  			"ca": "foo",
   263  			"cb": "bar",
   264  		},
   265  		"c": 5,
   266  	}
   267  	src = map[string]interface{}{
   268  		"a": false,
   269  		"b": map[string]interface{}{
   270  			"ca": 8,
   271  		},
   272  	}
   273  	expected = map[string]interface{}{
   274  		"a": dst["a"], "b": map[string]interface{}{
   275  			"ca": "foo",
   276  			"cb": "bar",
   277  		}, "c": dst["c"],
   278  	}
   279  
   280  	out, err = Merge(dst, src)
   281  	require.NoError(t, err)
   282  	assert.EqualValues(t, expected, out)
   283  }
   284  
   285  type coords struct {
   286  	X, Y int
   287  }
   288  
   289  func TestSameTypes(t *testing.T) {
   290  	data := []struct {
   291  		in  []interface{}
   292  		out bool
   293  	}{
   294  		{[]interface{}{}, true},
   295  		{[]interface{}{"a", "b"}, true},
   296  		{[]interface{}{1.0, 3.14}, true},
   297  		{[]interface{}{1, 3}, true},
   298  		{[]interface{}{true, false}, true},
   299  		{[]interface{}{1, 3.0}, false},
   300  		{[]interface{}{"a", nil}, false},
   301  		{[]interface{}{"a", true}, false},
   302  		{[]interface{}{coords{2, 3}, coords{3, 4}}, true},
   303  		{[]interface{}{coords{2, 3}, &coords{3, 4}}, false},
   304  	}
   305  
   306  	for _, d := range data {
   307  		assert.Equal(t, d.out, sameTypes(d.in))
   308  	}
   309  }
   310  
   311  func TestLessThan(t *testing.T) {
   312  	data := []struct {
   313  		left, right interface{}
   314  		key         string
   315  		out         bool
   316  	}{
   317  		{key: ""},
   318  		{left: "a", right: "b", out: true},
   319  		{left: "a", right: "a"},
   320  		{left: "b", right: "a"},
   321  		{left: 1.00, right: 3.14, out: true},
   322  		{left: 'a', right: 'A'},
   323  		{left: 'a', right: 'b', out: true},
   324  		{left: uint(0xff), right: uint(0x32)},
   325  		{left: 1, right: 3, out: true},
   326  		{left: true, right: false, out: false},
   327  		{left: map[string]interface{}{"foo": 1}, right: map[string]interface{}{"foo": 2}},
   328  		{
   329  			key:   "foo",
   330  			left:  map[string]interface{}{"foo": 1},
   331  			right: map[string]interface{}{"foo": 2},
   332  			out:   true,
   333  		},
   334  		{
   335  			key:   "bar",
   336  			left:  map[string]interface{}{"foo": 1},
   337  			right: map[string]interface{}{"foo": 2},
   338  		},
   339  		{key: "X", left: coords{}, right: coords{-1, 2}},
   340  		{key: "Y", left: &coords{1, 1}, right: &coords{-1, 2}, out: true},
   341  		{left: &coords{1, 1}, right: &coords{-1, 2}},
   342  		{key: "foo", left: &coords{1, 1}, right: &coords{-1, 2}},
   343  	}
   344  
   345  	for _, d := range data {
   346  		d := d
   347  		t.Run(fmt.Sprintf(`LessThan("%s")(<%T>%#v,%#v)==%v`, d.key, d.left, d.left, d.right, d.out), func(t *testing.T) {
   348  			assert.Equal(t, d.out, lessThan(d.key)(d.left, d.right))
   349  		})
   350  	}
   351  }
   352  
   353  func TestSort(t *testing.T) {
   354  	out, err := Sort("", 42)
   355  	require.Error(t, err)
   356  	assert.Nil(t, out)
   357  
   358  	data := []struct {
   359  		key string
   360  		in  interface{}
   361  		out []interface{}
   362  	}{
   363  		{
   364  			key: "",
   365  			in:  []string{"b", "c", "a", "d"},
   366  			out: []interface{}{"a", "b", "c", "d"},
   367  		},
   368  		{
   369  			key: "",
   370  			in:  []interface{}{"b", "c", "a", "d"},
   371  			out: []interface{}{"a", "b", "c", "d"},
   372  		},
   373  		{
   374  			key: "",
   375  			in:  []interface{}{"c", "a", "b", 3, 1, 2},
   376  			out: []interface{}{"c", "a", "b", 3, 1, 2},
   377  		},
   378  		{
   379  			key: "",
   380  			in:  nil,
   381  			out: nil,
   382  		},
   383  
   384  		{
   385  			key: "",
   386  			in: []map[string]interface{}{
   387  				{"name": "Bart", "age": 12},
   388  				{"age": 1, "name": "Maggie"},
   389  				{"name": "Lisa", "age": 6},
   390  			},
   391  			out: []interface{}{
   392  				map[string]interface{}{"name": "Bart", "age": 12},
   393  				map[string]interface{}{"age": 1, "name": "Maggie"},
   394  				map[string]interface{}{"name": "Lisa", "age": 6},
   395  			},
   396  		},
   397  		{
   398  			key: "name",
   399  			in: []map[string]interface{}{
   400  				{"name": "Bart", "age": 12},
   401  				{"age": 1, "name": "Maggie"},
   402  				{"name": "Lisa", "age": 6},
   403  			},
   404  			out: []interface{}{
   405  				map[string]interface{}{"name": "Bart", "age": 12},
   406  				map[string]interface{}{"name": "Lisa", "age": 6},
   407  				map[string]interface{}{"age": 1, "name": "Maggie"},
   408  			},
   409  		},
   410  		{
   411  			key: "age",
   412  			in: []map[string]interface{}{
   413  				{"name": "Bart", "age": 12},
   414  				{"age": 1, "name": "Maggie"},
   415  				{"name": "Lisa", "age": 6},
   416  			},
   417  			out: []interface{}{
   418  				map[string]interface{}{"age": 1, "name": "Maggie"},
   419  				map[string]interface{}{"name": "Lisa", "age": 6},
   420  				map[string]interface{}{"name": "Bart", "age": 12},
   421  			},
   422  		},
   423  		{
   424  			key: "y",
   425  			in: []map[string]int{
   426  				{"x": 54, "y": 6},
   427  				{"x": 13, "y": -8},
   428  				{"x": 1, "y": 0},
   429  			},
   430  			out: []interface{}{
   431  				map[string]int{"x": 13, "y": -8},
   432  				map[string]int{"x": 1, "y": 0},
   433  				map[string]int{"x": 54, "y": 6},
   434  			},
   435  		},
   436  		{
   437  			key: "X",
   438  			in: []coords{
   439  				{2, 4},
   440  				{3, 3},
   441  				{1, 5},
   442  			},
   443  			out: []interface{}{
   444  				coords{1, 5},
   445  				coords{2, 4},
   446  				coords{3, 3},
   447  			},
   448  		},
   449  		{
   450  			key: "X",
   451  			in: []*coords{
   452  				{2, 4},
   453  				{3, 3},
   454  				{1, 5},
   455  			},
   456  			out: []interface{}{
   457  				&coords{1, 5},
   458  				&coords{2, 4},
   459  				&coords{3, 3},
   460  			},
   461  		},
   462  	}
   463  
   464  	for _, d := range data {
   465  		d := d
   466  		t.Run(fmt.Sprintf(`Sort("%s",<%T>)==%#v`, d.key, d.in, d.out), func(t *testing.T) {
   467  			out, err := Sort(d.key, d.in)
   468  			require.NoError(t, err)
   469  			assert.EqualValues(t, d.out, out)
   470  		})
   471  	}
   472  }
   473  
   474  func TestFlatten(t *testing.T) {
   475  	data := []struct {
   476  		in       interface{}
   477  		expected []interface{}
   478  		depth    int
   479  	}{
   480  		{in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   481  		{in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   482  		{in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{[]string{}, []int{1, 2}, 3}},
   483  		{
   484  			in:       []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   485  			expected: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   486  		},
   487  		{depth: 1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   488  		{depth: 1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   489  		{depth: 1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
   490  		{
   491  			depth:    1,
   492  			in:       []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   493  			expected: []interface{}{"one", []int{1, 2}, 3},
   494  		},
   495  		{depth: 2, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   496  		{depth: 2, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   497  		{depth: 2, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
   498  		{
   499  			depth:    2,
   500  			in:       []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   501  			expected: []interface{}{"one", 1, 2, 3},
   502  		},
   503  		{
   504  			depth: 2,
   505  			in: []interface{}{
   506  				[]string{"one"},
   507  				[]interface{}{
   508  					[]interface{}{
   509  						[]int{1},
   510  						[]interface{}{2, []int{3}},
   511  					},
   512  					[]int{4, 5},
   513  				},
   514  				6,
   515  			},
   516  			expected: []interface{}{"one", []int{1}, []interface{}{2, []int{3}}, 4, 5, 6},
   517  		},
   518  		{depth: -1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   519  		{depth: -1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
   520  		{depth: -1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
   521  		{
   522  			depth:    -1,
   523  			in:       []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   524  			expected: []interface{}{"one", 1, 2, 3},
   525  		},
   526  		{
   527  			depth: -1,
   528  			in: []interface{}{
   529  				[]string{"one"},
   530  				[]interface{}{
   531  					[]interface{}{
   532  						[]int{1},
   533  						[]interface{}{2, []int{3}},
   534  					},
   535  					[]int{4, 5},
   536  				},
   537  				6,
   538  			},
   539  			expected: []interface{}{"one", 1, 2, 3, 4, 5, 6},
   540  		},
   541  	}
   542  
   543  	for _, d := range data {
   544  		out, err := Flatten(d.in, d.depth)
   545  		require.NoError(t, err)
   546  		assert.EqualValues(t, d.expected, out)
   547  	}
   548  
   549  	_, err := Flatten(42, -1)
   550  	require.Error(t, err)
   551  }
   552  
   553  func BenchmarkFlatten(b *testing.B) {
   554  	data := []interface{}{
   555  		[]int{1, 2, 3},
   556  		[3]int{1, 2, 3},
   557  		[]interface{}{[]string{}, []int{1, 2}, 3},
   558  		[]interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
   559  		[]interface{}{
   560  			[]string{"one"},
   561  			[]interface{}{
   562  				[]interface{}{
   563  					[]int{1},
   564  					[]interface{}{2, []int{3}},
   565  				},
   566  				[]int{4, 5},
   567  			},
   568  			6,
   569  		},
   570  	}
   571  	for depth := -1; depth <= 2; depth++ {
   572  		depth := depth
   573  		for _, d := range data {
   574  			d := d
   575  			b.Run(fmt.Sprintf("depth%d %T(%v)", depth, d, d), func(b *testing.B) {
   576  				for i := 0; i < b.N; i++ {
   577  					Flatten(d, depth)
   578  				}
   579  			})
   580  		}
   581  	}
   582  }
   583  
   584  func TestOmit(t *testing.T) {
   585  	in := map[string]interface{}{
   586  		"foo": "bar",
   587  		"bar": true,
   588  		"":    "baz",
   589  	}
   590  	assert.EqualValues(t, in, Omit(in, "baz"))
   591  
   592  	expected := map[string]interface{}{
   593  		"foo": "bar",
   594  		"bar": true,
   595  	}
   596  	assert.EqualValues(t, expected, Omit(in, ""))
   597  
   598  	expected = map[string]interface{}{
   599  		"": "baz",
   600  	}
   601  	assert.EqualValues(t, expected, Omit(in, "foo", "bar"))
   602  
   603  	assert.EqualValues(t, map[string]interface{}{}, Omit(in, "foo", "bar", ""))
   604  }
   605  
   606  func TestPick(t *testing.T) {
   607  	in := map[string]interface{}{
   608  		"foo": "bar",
   609  		"bar": true,
   610  		"":    "baz",
   611  	}
   612  	expected := map[string]interface{}{}
   613  	assert.EqualValues(t, expected, Pick(in, "baz"))
   614  
   615  	expected = map[string]interface{}{
   616  		"": "baz",
   617  	}
   618  	assert.EqualValues(t, expected, Pick(in, ""))
   619  
   620  	expected = map[string]interface{}{
   621  		"foo": "bar",
   622  		"bar": true,
   623  	}
   624  	assert.EqualValues(t, expected, Pick(in, "foo", "bar"))
   625  
   626  	assert.EqualValues(t, in, Pick(in, "foo", "bar", ""))
   627  }