github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/tpl/collections/collections_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  	"errors"
    18  	"fmt"
    19  	"html/template"
    20  	"math/rand"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/gohugoio/hugo/common/maps"
    26  
    27  	qt "github.com/frankban/quicktest"
    28  	"github.com/gohugoio/hugo/common/loggers"
    29  	"github.com/gohugoio/hugo/config"
    30  	"github.com/gohugoio/hugo/deps"
    31  	"github.com/gohugoio/hugo/helpers"
    32  	"github.com/gohugoio/hugo/hugofs"
    33  	"github.com/gohugoio/hugo/langs"
    34  	"github.com/spf13/afero"
    35  	
    36  )
    37  
    38  type tstNoStringer struct{}
    39  
    40  func TestAfter(t *testing.T) {
    41  	t.Parallel()
    42  	c := qt.New(t)
    43  
    44  	ns := New(&deps.Deps{})
    45  
    46  	for i, test := range []struct {
    47  		index  interface{}
    48  		seq    interface{}
    49  		expect interface{}
    50  	}{
    51  		{int(2), []string{"a", "b", "c", "d"}, []string{"c", "d"}},
    52  		{int32(3), []string{"a", "b"}, []string{}},
    53  		{int64(2), []int{100, 200, 300}, []int{300}},
    54  		{100, []int{100, 200}, []int{}},
    55  		{"1", []int{100, 200, 300}, []int{200, 300}},
    56  		{0, []int{100, 200, 300, 400, 500}, []int{100, 200, 300, 400, 500}},
    57  		{0, []string{"a", "b", "c", "d", "e"}, []string{"a", "b", "c", "d", "e"}},
    58  		{int64(-1), []int{100, 200, 300}, false},
    59  		{"noint", []int{100, 200, 300}, false},
    60  		{2, []string{}, []string{}},
    61  		{1, nil, false},
    62  		{nil, []int{100}, false},
    63  		{1, t, false},
    64  		{1, (*string)(nil), false},
    65  	} {
    66  		errMsg := qt.Commentf("[%d] %v", i, test)
    67  
    68  		result, err := ns.After(test.index, test.seq)
    69  
    70  		if b, ok := test.expect.(bool); ok && !b {
    71  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
    72  			continue
    73  		}
    74  
    75  		c.Assert(err, qt.IsNil, errMsg)
    76  		c.Assert(result, qt.DeepEquals, test.expect, errMsg)
    77  	}
    78  }
    79  
    80  type tstGrouper struct {
    81  }
    82  
    83  type tstGroupers []*tstGrouper
    84  
    85  func (g tstGrouper) Group(key interface{}, items interface{}) (interface{}, error) {
    86  	ilen := reflect.ValueOf(items).Len()
    87  	return fmt.Sprintf("%v(%d)", key, ilen), nil
    88  }
    89  
    90  type tstGrouper2 struct {
    91  }
    92  
    93  func (g *tstGrouper2) Group(key interface{}, items interface{}) (interface{}, error) {
    94  	ilen := reflect.ValueOf(items).Len()
    95  	return fmt.Sprintf("%v(%d)", key, ilen), nil
    96  }
    97  
    98  func TestGroup(t *testing.T) {
    99  	t.Parallel()
   100  	c := qt.New(t)
   101  	ns := New(&deps.Deps{})
   102  
   103  	for i, test := range []struct {
   104  		key    interface{}
   105  		items  interface{}
   106  		expect interface{}
   107  	}{
   108  		{"a", []*tstGrouper{{}, {}}, "a(2)"},
   109  		{"b", tstGroupers{&tstGrouper{}, &tstGrouper{}}, "b(2)"},
   110  		{"a", []tstGrouper{{}, {}}, "a(2)"},
   111  		{"a", []*tstGrouper2{{}, {}}, "a(2)"},
   112  		{"b", []tstGrouper2{{}, {}}, "b(2)"},
   113  		{"a", []*tstGrouper{}, "a(0)"},
   114  		{"a", []string{"a", "b"}, false},
   115  		{"a", "asdf", false},
   116  		{"a", nil, false},
   117  		{nil, []*tstGrouper{{}, {}}, false},
   118  	} {
   119  		errMsg := qt.Commentf("[%d] %v", i, test)
   120  
   121  		result, err := ns.Group(test.key, test.items)
   122  
   123  		if b, ok := test.expect.(bool); ok && !b {
   124  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   125  			continue
   126  		}
   127  
   128  		c.Assert(err, qt.IsNil, errMsg)
   129  		c.Assert(result, qt.Equals, test.expect, errMsg)
   130  	}
   131  }
   132  
   133  func TestDelimit(t *testing.T) {
   134  	t.Parallel()
   135  	c := qt.New(t)
   136  
   137  	ns := New(&deps.Deps{})
   138  
   139  	for i, test := range []struct {
   140  		seq       interface{}
   141  		delimiter interface{}
   142  		last      interface{}
   143  		expect    template.HTML
   144  	}{
   145  		{[]string{"class1", "class2", "class3"}, " ", nil, "class1 class2 class3"},
   146  		{[]int{1, 2, 3, 4, 5}, ",", nil, "1,2,3,4,5"},
   147  		{[]int{1, 2, 3, 4, 5}, ", ", nil, "1, 2, 3, 4, 5"},
   148  		{[]string{"class1", "class2", "class3"}, " ", " and ", "class1 class2 and class3"},
   149  		{[]int{1, 2, 3, 4, 5}, ",", ",", "1,2,3,4,5"},
   150  		{[]int{1, 2, 3, 4, 5}, ", ", ", and ", "1, 2, 3, 4, and 5"},
   151  		// test maps with and without sorting required
   152  		{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", nil, "10--20--30--40--50"},
   153  		{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", nil, "30--20--10--40--50"},
   154  		{map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", nil, "10--20--30--40--50"},
   155  		{map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", nil, "30--20--10--40--50"},
   156  		{map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", nil, "50--40--10--30--20"},
   157  		{map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", nil, "10--20--30--40--50"},
   158  		{map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", nil, "30--20--10--40--50"},
   159  		{map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, "--", nil, "30--20--10--40--50"},
   160  		// test maps with a last delimiter
   161  		{map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", "--and--", "10--20--30--40--and--50"},
   162  		{map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", "--and--", "30--20--10--40--and--50"},
   163  		{map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", "--and--", "10--20--30--40--and--50"},
   164  		{map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", "--and--", "30--20--10--40--and--50"},
   165  		{map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", "--and--", "50--40--10--30--and--20"},
   166  		{map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", "--and--", "10--20--30--40--and--50"},
   167  		{map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
   168  		{map[float64]string{3.5: "10", 2.5: "20", 1.5: "30", 4.5: "40", 5.5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
   169  	} {
   170  		errMsg := qt.Commentf("[%d] %v", i, test)
   171  
   172  		var result template.HTML
   173  		var err error
   174  
   175  		if test.last == nil {
   176  			result, err = ns.Delimit(test.seq, test.delimiter)
   177  		} else {
   178  			result, err = ns.Delimit(test.seq, test.delimiter, test.last)
   179  		}
   180  
   181  		c.Assert(err, qt.IsNil, errMsg)
   182  		c.Assert(result, qt.Equals, test.expect, errMsg)
   183  	}
   184  }
   185  
   186  func TestDictionary(t *testing.T) {
   187  	c := qt.New(t)
   188  
   189  	ns := New(&deps.Deps{})
   190  
   191  	for i, test := range []struct {
   192  		values []interface{}
   193  		expect interface{}
   194  	}{
   195  		{[]interface{}{"a", "b"}, map[string]interface{}{"a": "b"}},
   196  		{[]interface{}{[]string{"a", "b"}, "c"}, map[string]interface{}{"a": map[string]interface{}{"b": "c"}}},
   197  		{
   198  			[]interface{}{[]string{"a", "b"}, "c", []string{"a", "b2"}, "c2", "b", "c"},
   199  			map[string]interface{}{"a": map[string]interface{}{"b": "c", "b2": "c2"}, "b": "c"},
   200  		},
   201  		{[]interface{}{"a", 12, "b", []int{4}}, map[string]interface{}{"a": 12, "b": []int{4}}},
   202  		// errors
   203  		{[]interface{}{5, "b"}, false},
   204  		{[]interface{}{"a", "b", "c"}, false},
   205  	} {
   206  		i := i
   207  		test := test
   208  		c.Run(fmt.Sprint(i), func(c *qt.C) {
   209  			c.Parallel()
   210  			errMsg := qt.Commentf("[%d] %v", i, test.values)
   211  
   212  			result, err := ns.Dictionary(test.values...)
   213  
   214  			if b, ok := test.expect.(bool); ok && !b {
   215  				c.Assert(err, qt.Not(qt.IsNil), errMsg)
   216  				return
   217  			}
   218  
   219  			c.Assert(err, qt.IsNil, errMsg)
   220  			c.Assert(result, qt.DeepEquals, test.expect, qt.Commentf(fmt.Sprint(result)))
   221  		})
   222  	}
   223  }
   224  
   225  func TestReverse(t *testing.T) {
   226  	t.Parallel()
   227  	c := qt.New(t)
   228  	ns := New(&deps.Deps{})
   229  
   230  	s := []string{"a", "b", "c"}
   231  	reversed, err := ns.Reverse(s)
   232  	c.Assert(err, qt.IsNil)
   233  	c.Assert(reversed, qt.DeepEquals, []string{"c", "b", "a"}, qt.Commentf(fmt.Sprint(reversed)))
   234  	c.Assert(s, qt.DeepEquals, []string{"a", "b", "c"})
   235  
   236  	reversed, err = ns.Reverse(nil)
   237  	c.Assert(err, qt.IsNil)
   238  	c.Assert(reversed, qt.IsNil)
   239  	_, err = ns.Reverse(43)
   240  	c.Assert(err, qt.Not(qt.IsNil))
   241  }
   242  
   243  func TestEchoParam(t *testing.T) {
   244  	t.Parallel()
   245  	c := qt.New(t)
   246  
   247  	ns := New(&deps.Deps{})
   248  
   249  	for i, test := range []struct {
   250  		a      interface{}
   251  		key    interface{}
   252  		expect interface{}
   253  	}{
   254  		{[]int{1, 2, 3}, 1, int64(2)},
   255  		{[]uint{1, 2, 3}, 1, uint64(2)},
   256  		{[]float64{1.1, 2.2, 3.3}, 1, float64(2.2)},
   257  		{[]string{"foo", "bar", "baz"}, 1, "bar"},
   258  		{[]TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}}, 1, ""},
   259  		{map[string]int{"foo": 1, "bar": 2, "baz": 3}, "bar", int64(2)},
   260  		{map[string]uint{"foo": 1, "bar": 2, "baz": 3}, "bar", uint64(2)},
   261  		{map[string]float64{"foo": 1.1, "bar": 2.2, "baz": 3.3}, "bar", float64(2.2)},
   262  		{map[string]string{"foo": "FOO", "bar": "BAR", "baz": "BAZ"}, "bar", "BAR"},
   263  		{map[string]TstX{"foo": {A: "a", B: "b"}, "bar": {A: "c", B: "d"}, "baz": {A: "e", B: "f"}}, "bar", ""},
   264  		{map[string]interface{}{"foo": nil}, "foo", ""},
   265  		{(*[]string)(nil), "bar", ""},
   266  	} {
   267  		errMsg := qt.Commentf("[%d] %v", i, test)
   268  
   269  		result := ns.EchoParam(test.a, test.key)
   270  
   271  		c.Assert(result, qt.Equals, test.expect, errMsg)
   272  	}
   273  }
   274  
   275  func TestFirst(t *testing.T) {
   276  	t.Parallel()
   277  	c := qt.New(t)
   278  
   279  	ns := New(&deps.Deps{})
   280  
   281  	for i, test := range []struct {
   282  		limit  interface{}
   283  		seq    interface{}
   284  		expect interface{}
   285  	}{
   286  		{int(2), []string{"a", "b", "c"}, []string{"a", "b"}},
   287  		{int32(3), []string{"a", "b"}, []string{"a", "b"}},
   288  		{int64(2), []int{100, 200, 300}, []int{100, 200}},
   289  		{100, []int{100, 200}, []int{100, 200}},
   290  		{"1", []int{100, 200, 300}, []int{100}},
   291  		{0, []string{"h", "u", "g", "o"}, []string{}},
   292  		{int64(-1), []int{100, 200, 300}, false},
   293  		{"noint", []int{100, 200, 300}, false},
   294  		{1, nil, false},
   295  		{nil, []int{100}, false},
   296  		{1, t, false},
   297  		{1, (*string)(nil), false},
   298  	} {
   299  		errMsg := qt.Commentf("[%d] %v", i, test)
   300  
   301  		result, err := ns.First(test.limit, test.seq)
   302  
   303  		if b, ok := test.expect.(bool); ok && !b {
   304  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   305  			continue
   306  		}
   307  
   308  		c.Assert(err, qt.IsNil)
   309  		c.Assert(result, qt.DeepEquals, test.expect, errMsg)
   310  	}
   311  }
   312  
   313  func TestIn(t *testing.T) {
   314  	t.Parallel()
   315  	c := qt.New(t)
   316  
   317  	ns := New(&deps.Deps{})
   318  
   319  	for i, test := range []struct {
   320  		l1     interface{}
   321  		l2     interface{}
   322  		expect bool
   323  	}{
   324  		{[]string{"a", "b", "c"}, "b", true},
   325  		{[]interface{}{"a", "b", "c"}, "b", true},
   326  		{[]interface{}{"a", "b", "c"}, "d", false},
   327  		{[]string{"a", "b", "c"}, "d", false},
   328  		{[]string{"a", "12", "c"}, 12, false},
   329  		{[]string{"a", "b", "c"}, nil, false},
   330  		{[]int{1, 2, 4}, 2, true},
   331  		{[]interface{}{1, 2, 4}, 2, true},
   332  		{[]interface{}{1, 2, 4}, nil, false},
   333  		{[]interface{}{nil}, nil, false},
   334  		{[]int{1, 2, 4}, 3, false},
   335  		{[]float64{1.23, 2.45, 4.67}, 1.23, true},
   336  		{[]float64{1.234567, 2.45, 4.67}, 1.234568, false},
   337  		{[]float64{1, 2, 3}, 1, true},
   338  		{[]float32{1, 2, 3}, 1, true},
   339  		{"this substring should be found", "substring", true},
   340  		{"this substring should not be found", "subseastring", false},
   341  		{nil, "foo", false},
   342  		// Pointers
   343  		{pagesPtr{p1, p2, p3, p2}, p2, true},
   344  		{pagesPtr{p1, p2, p3, p2}, p4, false},
   345  		// Structs
   346  		{pagesVals{p3v, p2v, p3v, p2v}, p2v, true},
   347  		{pagesVals{p3v, p2v, p3v, p2v}, p4v, false},
   348  		// template.HTML
   349  		{template.HTML("this substring should be found"), "substring", true},
   350  		{template.HTML("this substring should not be found"), "subseastring", false},
   351  		// Uncomparable, use hashstructure
   352  		{[]string{"a", "b"}, []string{"a", "b"}, false},
   353  		{[][]string{{"a", "b"}}, []string{"a", "b"}, true},
   354  	} {
   355  
   356  		errMsg := qt.Commentf("[%d] %v", i, test)
   357  
   358  		result, err := ns.In(test.l1, test.l2)
   359  		c.Assert(err, qt.IsNil)
   360  		c.Assert(result, qt.Equals, test.expect, errMsg)
   361  	}
   362  }
   363  
   364  type testPage struct {
   365  	Title string
   366  }
   367  
   368  func (p testPage) String() string {
   369  	return "p-" + p.Title
   370  }
   371  
   372  type (
   373  	pagesPtr  []*testPage
   374  	pagesVals []testPage
   375  )
   376  
   377  var (
   378  	p1 = &testPage{"A"}
   379  	p2 = &testPage{"B"}
   380  	p3 = &testPage{"C"}
   381  	p4 = &testPage{"D"}
   382  
   383  	p1v = testPage{"A"}
   384  	p2v = testPage{"B"}
   385  	p3v = testPage{"C"}
   386  	p4v = testPage{"D"}
   387  )
   388  
   389  func TestIntersect(t *testing.T) {
   390  	t.Parallel()
   391  	c := qt.New(t)
   392  
   393  	ns := New(&deps.Deps{})
   394  
   395  	for i, test := range []struct {
   396  		l1, l2 interface{}
   397  		expect interface{}
   398  	}{
   399  		{[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b"}},
   400  		{[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b"}},
   401  		{[]string{"a", "b", "c"}, []string{"d", "e"}, []string{}},
   402  		{[]string{}, []string{}, []string{}},
   403  		{[]string{"a", "b"}, nil, []interface{}{}},
   404  		{nil, []string{"a", "b"}, []interface{}{}},
   405  		{nil, nil, []interface{}{}},
   406  		{[]string{"1", "2"}, []int{1, 2}, []string{}},
   407  		{[]int{1, 2}, []string{"1", "2"}, []int{}},
   408  		{[]int{1, 2, 4}, []int{2, 4}, []int{2, 4}},
   409  		{[]int{2, 4}, []int{1, 2, 4}, []int{2, 4}},
   410  		{[]int{1, 2, 4}, []int{3, 6}, []int{}},
   411  		{[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4}},
   412  
   413  		// []interface{} ∩ []interface{}
   414  		{[]interface{}{"a", "b", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b"}},
   415  		{[]interface{}{1, 2, 3}, []interface{}{1, 2, 2}, []interface{}{1, 2}},
   416  		{[]interface{}{int8(1), int8(2), int8(3)}, []interface{}{int8(1), int8(2), int8(2)}, []interface{}{int8(1), int8(2)}},
   417  		{[]interface{}{int16(1), int16(2), int16(3)}, []interface{}{int16(1), int16(2), int16(2)}, []interface{}{int16(1), int16(2)}},
   418  		{[]interface{}{int32(1), int32(2), int32(3)}, []interface{}{int32(1), int32(2), int32(2)}, []interface{}{int32(1), int32(2)}},
   419  		{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(1), int64(2), int64(2)}, []interface{}{int64(1), int64(2)}},
   420  		{[]interface{}{float32(1), float32(2), float32(3)}, []interface{}{float32(1), float32(2), float32(2)}, []interface{}{float32(1), float32(2)}},
   421  		{[]interface{}{float64(1), float64(2), float64(3)}, []interface{}{float64(1), float64(2), float64(2)}, []interface{}{float64(1), float64(2)}},
   422  
   423  		// []interface{} ∩ []T
   424  		{[]interface{}{"a", "b", "c"}, []string{"a", "b", "b"}, []interface{}{"a", "b"}},
   425  		{[]interface{}{1, 2, 3}, []int{1, 2, 2}, []interface{}{1, 2}},
   426  		{[]interface{}{int8(1), int8(2), int8(3)}, []int8{1, 2, 2}, []interface{}{int8(1), int8(2)}},
   427  		{[]interface{}{int16(1), int16(2), int16(3)}, []int16{1, 2, 2}, []interface{}{int16(1), int16(2)}},
   428  		{[]interface{}{int32(1), int32(2), int32(3)}, []int32{1, 2, 2}, []interface{}{int32(1), int32(2)}},
   429  		{[]interface{}{int64(1), int64(2), int64(3)}, []int64{1, 2, 2}, []interface{}{int64(1), int64(2)}},
   430  		{[]interface{}{uint(1), uint(2), uint(3)}, []uint{1, 2, 2}, []interface{}{uint(1), uint(2)}},
   431  		{[]interface{}{float32(1), float32(2), float32(3)}, []float32{1, 2, 2}, []interface{}{float32(1), float32(2)}},
   432  		{[]interface{}{float64(1), float64(2), float64(3)}, []float64{1, 2, 2}, []interface{}{float64(1), float64(2)}},
   433  
   434  		// []T ∩ []interface{}
   435  		{[]string{"a", "b", "c"}, []interface{}{"a", "b", "b"}, []string{"a", "b"}},
   436  		{[]int{1, 2, 3}, []interface{}{1, 2, 2}, []int{1, 2}},
   437  		{[]int8{1, 2, 3}, []interface{}{int8(1), int8(2), int8(2)}, []int8{1, 2}},
   438  		{[]int16{1, 2, 3}, []interface{}{int16(1), int16(2), int16(2)}, []int16{1, 2}},
   439  		{[]int32{1, 2, 3}, []interface{}{int32(1), int32(2), int32(2)}, []int32{1, 2}},
   440  		{[]int64{1, 2, 3}, []interface{}{int64(1), int64(2), int64(2)}, []int64{1, 2}},
   441  		{[]float32{1, 2, 3}, []interface{}{float32(1), float32(2), float32(2)}, []float32{1, 2}},
   442  		{[]float64{1, 2, 3}, []interface{}{float64(1), float64(2), float64(2)}, []float64{1, 2}},
   443  
   444  		// Structs
   445  		{pagesPtr{p1, p4, p2, p3}, pagesPtr{p4, p2, p2}, pagesPtr{p4, p2}},
   446  		{pagesVals{p1v, p4v, p2v, p3v}, pagesVals{p1v, p3v, p3v}, pagesVals{p1v, p3v}},
   447  		{[]interface{}{p1, p4, p2, p3}, []interface{}{p4, p2, p2}, []interface{}{p4, p2}},
   448  		{[]interface{}{p1v, p4v, p2v, p3v}, []interface{}{p1v, p3v, p3v}, []interface{}{p1v, p3v}},
   449  		{pagesPtr{p1, p4, p2, p3}, pagesPtr{}, pagesPtr{}},
   450  		{pagesVals{}, pagesVals{p1v, p3v, p3v}, pagesVals{}},
   451  		{[]interface{}{p1, p4, p2, p3}, []interface{}{}, []interface{}{}},
   452  		{[]interface{}{}, []interface{}{p1v, p3v, p3v}, []interface{}{}},
   453  
   454  		// errors
   455  		{"not array or slice", []string{"a"}, false},
   456  		{[]string{"a"}, "not array or slice", false},
   457  
   458  		// uncomparable types - #3820
   459  		{[]map[int]int{{1: 1}, {2: 2}}, []map[int]int{{2: 2}, {3: 3}}, false},
   460  		{[][]int{{1, 1}, {1, 2}}, [][]int{{1, 2}, {1, 2}, {1, 3}}, false},
   461  		{[]int{1, 1}, [][]int{{1, 2}, {1, 2}, {1, 3}}, false},
   462  	} {
   463  
   464  		errMsg := qt.Commentf("[%d] %v", i, test)
   465  
   466  		result, err := ns.Intersect(test.l1, test.l2)
   467  
   468  		if b, ok := test.expect.(bool); ok && !b {
   469  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   470  			continue
   471  		}
   472  
   473  		c.Assert(err, qt.IsNil, errMsg)
   474  		if !reflect.DeepEqual(result, test.expect) {
   475  			t.Fatalf("[%d] Got\n%v expected\n%v", i, result, test.expect)
   476  		}
   477  	}
   478  }
   479  
   480  func TestIsSet(t *testing.T) {
   481  	t.Parallel()
   482  	c := qt.New(t)
   483  	ns := newTestNs()
   484  
   485  	for i, test := range []struct {
   486  		a      interface{}
   487  		key    interface{}
   488  		expect bool
   489  		isErr  bool
   490  	}{
   491  		{[]interface{}{1, 2, 3, 5}, 2, true, false},
   492  		{[]interface{}{1, 2, 3, 5}, "2", true, false},
   493  		{[]interface{}{1, 2, 3, 5}, 2.0, true, false},
   494  
   495  		{[]interface{}{1, 2, 3, 5}, 22, false, false},
   496  
   497  		{map[string]interface{}{"a": 1, "b": 2}, "b", true, false},
   498  		{map[string]interface{}{"a": 1, "b": 2}, "bc", false, false},
   499  
   500  		{time.Now(), "Day", false, false},
   501  		{nil, "nil", false, false},
   502  		{[]interface{}{1, 2, 3, 5}, TstX{}, false, true},
   503  	} {
   504  		errMsg := qt.Commentf("[%d] %v", i, test)
   505  
   506  		result, err := ns.IsSet(test.a, test.key)
   507  		if test.isErr {
   508  			continue
   509  		}
   510  
   511  		c.Assert(err, qt.IsNil, errMsg)
   512  		c.Assert(result, qt.Equals, test.expect, errMsg)
   513  	}
   514  }
   515  
   516  func TestLast(t *testing.T) {
   517  	t.Parallel()
   518  	c := qt.New(t)
   519  
   520  	ns := New(&deps.Deps{})
   521  
   522  	for i, test := range []struct {
   523  		limit  interface{}
   524  		seq    interface{}
   525  		expect interface{}
   526  	}{
   527  		{int(2), []string{"a", "b", "c"}, []string{"b", "c"}},
   528  		{int32(3), []string{"a", "b"}, []string{"a", "b"}},
   529  		{int64(2), []int{100, 200, 300}, []int{200, 300}},
   530  		{100, []int{100, 200}, []int{100, 200}},
   531  		{"1", []int{100, 200, 300}, []int{300}},
   532  		{"0", []int{100, 200, 300}, []int{}},
   533  		{"0", []string{"a", "b", "c"}, []string{}},
   534  		// errors
   535  		{int64(-1), []int{100, 200, 300}, false},
   536  		{"noint", []int{100, 200, 300}, false},
   537  		{1, nil, false},
   538  		{nil, []int{100}, false},
   539  		{1, t, false},
   540  		{1, (*string)(nil), false},
   541  	} {
   542  		errMsg := qt.Commentf("[%d] %v", i, test)
   543  
   544  		result, err := ns.Last(test.limit, test.seq)
   545  
   546  		if b, ok := test.expect.(bool); ok && !b {
   547  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   548  			continue
   549  		}
   550  
   551  		c.Assert(err, qt.IsNil, errMsg)
   552  		c.Assert(result, qt.DeepEquals, test.expect, errMsg)
   553  	}
   554  }
   555  
   556  func TestQuerify(t *testing.T) {
   557  	t.Parallel()
   558  	c := qt.New(t)
   559  	ns := New(&deps.Deps{})
   560  
   561  	for i, test := range []struct {
   562  		params []interface{}
   563  		expect interface{}
   564  	}{
   565  		{[]interface{}{"a", "b"}, "a=b"},
   566  		{[]interface{}{"a", "b", "c", "d", "f", " &"}, `a=b&c=d&f=+%26`},
   567  		{[]interface{}{[]string{"a", "b"}}, "a=b"},
   568  		{[]interface{}{[]string{"a", "b", "c", "d", "f", " &"}}, `a=b&c=d&f=+%26`},
   569  		{[]interface{}{[]interface{}{"x", "y"}}, `x=y`},
   570  		{[]interface{}{[]interface{}{"x", 5}}, `x=5`},
   571  		// errors
   572  		{[]interface{}{5, "b"}, false},
   573  		{[]interface{}{"a", "b", "c"}, false},
   574  		{[]interface{}{[]string{"a", "b", "c"}}, false},
   575  		{[]interface{}{[]string{"a", "b"}, "c"}, false},
   576  		{[]interface{}{[]interface{}{"c", "d", "e"}}, false},
   577  	} {
   578  		errMsg := qt.Commentf("[%d] %v", i, test.params)
   579  
   580  		result, err := ns.Querify(test.params...)
   581  
   582  		if b, ok := test.expect.(bool); ok && !b {
   583  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   584  			continue
   585  		}
   586  
   587  		c.Assert(err, qt.IsNil, errMsg)
   588  		c.Assert(result, qt.Equals, test.expect, errMsg)
   589  	}
   590  }
   591  
   592  func BenchmarkQuerify(b *testing.B) {
   593  	ns := New(&deps.Deps{})
   594  	params := []interface{}{"a", "b", "c", "d", "f", " &"}
   595  
   596  	b.ResetTimer()
   597  	for i := 0; i < b.N; i++ {
   598  		_, err := ns.Querify(params...)
   599  		if err != nil {
   600  			b.Fatal(err)
   601  		}
   602  	}
   603  }
   604  
   605  func BenchmarkQuerifySlice(b *testing.B) {
   606  	ns := New(&deps.Deps{})
   607  	params := []string{"a", "b", "c", "d", "f", " &"}
   608  
   609  	b.ResetTimer()
   610  	for i := 0; i < b.N; i++ {
   611  		_, err := ns.Querify(params)
   612  		if err != nil {
   613  			b.Fatal(err)
   614  		}
   615  	}
   616  }
   617  
   618  func TestSeq(t *testing.T) {
   619  	t.Parallel()
   620  	c := qt.New(t)
   621  	ns := New(&deps.Deps{})
   622  
   623  	for i, test := range []struct {
   624  		args   []interface{}
   625  		expect interface{}
   626  	}{
   627  		{[]interface{}{-2, 5}, []int{-2, -1, 0, 1, 2, 3, 4, 5}},
   628  		{[]interface{}{1, 2, 4}, []int{1, 3}},
   629  		{[]interface{}{1}, []int{1}},
   630  		{[]interface{}{3}, []int{1, 2, 3}},
   631  		{[]interface{}{3.2}, []int{1, 2, 3}},
   632  		{[]interface{}{0}, []int{}},
   633  		{[]interface{}{-1}, []int{-1}},
   634  		{[]interface{}{-3}, []int{-1, -2, -3}},
   635  		{[]interface{}{3, -2}, []int{3, 2, 1, 0, -1, -2}},
   636  		{[]interface{}{6, -2, 2}, []int{6, 4, 2}},
   637  		// errors
   638  		{[]interface{}{1, 0, 2}, false},
   639  		{[]interface{}{1, -1, 2}, false},
   640  		{[]interface{}{2, 1, 1}, false},
   641  		{[]interface{}{2, 1, 1, 1}, false},
   642  		{[]interface{}{2001}, false},
   643  		{[]interface{}{}, false},
   644  		{[]interface{}{0, -1000000}, false},
   645  		{[]interface{}{tstNoStringer{}}, false},
   646  		{nil, false},
   647  	} {
   648  		errMsg := qt.Commentf("[%d] %v", i, test)
   649  
   650  		result, err := ns.Seq(test.args...)
   651  
   652  		if b, ok := test.expect.(bool); ok && !b {
   653  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   654  			continue
   655  		}
   656  
   657  		c.Assert(err, qt.IsNil, errMsg)
   658  		c.Assert(result, qt.DeepEquals, test.expect, errMsg)
   659  	}
   660  }
   661  
   662  func TestShuffle(t *testing.T) {
   663  	t.Parallel()
   664  	c := qt.New(t)
   665  	ns := New(&deps.Deps{})
   666  
   667  	for i, test := range []struct {
   668  		seq     interface{}
   669  		success bool
   670  	}{
   671  		{[]string{"a", "b", "c", "d"}, true},
   672  		{[]int{100, 200, 300}, true},
   673  		{[]int{100, 200, 300}, true},
   674  		{[]int{100, 200}, true},
   675  		{[]string{"a", "b"}, true},
   676  		{[]int{100, 200, 300}, true},
   677  		{[]int{100, 200, 300}, true},
   678  		{[]int{100}, true},
   679  		// errors
   680  		{nil, false},
   681  		{t, false},
   682  		{(*string)(nil), false},
   683  	} {
   684  		errMsg := qt.Commentf("[%d] %v", i, test)
   685  
   686  		result, err := ns.Shuffle(test.seq)
   687  
   688  		if !test.success {
   689  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   690  			continue
   691  		}
   692  
   693  		c.Assert(err, qt.IsNil, errMsg)
   694  
   695  		resultv := reflect.ValueOf(result)
   696  		seqv := reflect.ValueOf(test.seq)
   697  
   698  		c.Assert(seqv.Len(), qt.Equals, resultv.Len(), errMsg)
   699  	}
   700  }
   701  
   702  func TestShuffleRandomising(t *testing.T) {
   703  	t.Parallel()
   704  	c := qt.New(t)
   705  	ns := New(&deps.Deps{})
   706  
   707  	// Note that this test can fail with false negative result if the shuffle
   708  	// of the sequence happens to be the same as the original sequence. However
   709  	// the probability of the event is 10^-158 which is negligible.
   710  	seqLen := 100
   711  	rand.Seed(time.Now().UTC().UnixNano())
   712  
   713  	for _, test := range []struct {
   714  		seq []int
   715  	}{
   716  		{rand.Perm(seqLen)},
   717  	} {
   718  		result, err := ns.Shuffle(test.seq)
   719  		resultv := reflect.ValueOf(result)
   720  
   721  		c.Assert(err, qt.IsNil)
   722  
   723  		allSame := true
   724  		for i, v := range test.seq {
   725  			allSame = allSame && (resultv.Index(i).Interface() == v)
   726  		}
   727  
   728  		c.Assert(allSame, qt.Equals, false)
   729  	}
   730  }
   731  
   732  // Also see tests in commons/collection.
   733  func TestSlice(t *testing.T) {
   734  	t.Parallel()
   735  	c := qt.New(t)
   736  	ns := New(&deps.Deps{})
   737  
   738  	for i, test := range []struct {
   739  		args     []interface{}
   740  		expected interface{}
   741  	}{
   742  		{[]interface{}{"a", "b"}, []string{"a", "b"}},
   743  		{[]interface{}{}, []interface{}{}},
   744  		{[]interface{}{nil}, []interface{}{nil}},
   745  		{[]interface{}{5, "b"}, []interface{}{5, "b"}},
   746  		{[]interface{}{tstNoStringer{}}, []tstNoStringer{{}}},
   747  	} {
   748  		errMsg := qt.Commentf("[%d] %v", i, test.args)
   749  
   750  		result := ns.Slice(test.args...)
   751  
   752  		c.Assert(result, qt.DeepEquals, test.expected, errMsg)
   753  	}
   754  }
   755  
   756  func TestUnion(t *testing.T) {
   757  	t.Parallel()
   758  	c := qt.New(t)
   759  
   760  	ns := New(&deps.Deps{})
   761  
   762  	for i, test := range []struct {
   763  		l1     interface{}
   764  		l2     interface{}
   765  		expect interface{}
   766  		isErr  bool
   767  	}{
   768  		{nil, nil, []interface{}{}, false},
   769  		{nil, []string{"a", "b"}, []string{"a", "b"}, false},
   770  		{[]string{"a", "b"}, nil, []string{"a", "b"}, false},
   771  
   772  		// []A ∪ []B
   773  		{[]string{"1", "2"}, []int{3}, []string{}, false},
   774  		{[]int{1, 2}, []string{"1", "2"}, []int{}, false},
   775  
   776  		// []T ∪ []T
   777  		{[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b", "c"}, false},
   778  		{[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
   779  		{[]string{"a", "b", "c"}, []string{"d", "e"}, []string{"a", "b", "c", "d", "e"}, false},
   780  		{[]string{}, []string{}, []string{}, false},
   781  		{[]int{1, 2, 3}, []int{3, 4, 5}, []int{1, 2, 3, 4, 5}, false},
   782  		{[]int{1, 2, 3}, []int{1, 2, 3}, []int{1, 2, 3}, false},
   783  		{[]int{1, 2, 4}, []int{2, 4}, []int{1, 2, 4}, false},
   784  		{[]int{2, 4}, []int{1, 2, 4}, []int{2, 4, 1}, false},
   785  		{[]int{1, 2, 4}, []int{3, 6}, []int{1, 2, 4, 3, 6}, false},
   786  		{[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
   787  		{[]interface{}{"a", "b", "c", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false},
   788  
   789  		// []T ∪ []interface{}
   790  		{[]string{"1", "2"}, []interface{}{"9"}, []string{"1", "2", "9"}, false},
   791  		{[]int{2, 4}, []interface{}{1, 2, 4}, []int{2, 4, 1}, false},
   792  		{[]int8{2, 4}, []interface{}{int8(1), int8(2), int8(4)}, []int8{2, 4, 1}, false},
   793  		{[]int8{2, 4}, []interface{}{1, 2, 4}, []int8{2, 4, 1}, false},
   794  		{[]int16{2, 4}, []interface{}{1, 2, 4}, []int16{2, 4, 1}, false},
   795  		{[]int32{2, 4}, []interface{}{1, 2, 4}, []int32{2, 4, 1}, false},
   796  		{[]int64{2, 4}, []interface{}{1, 2, 4}, []int64{2, 4, 1}, false},
   797  
   798  		{[]float64{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
   799  		{[]float32{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float32{2.2, 4.4, 1.1}, false},
   800  
   801  		// []interface{} ∪ []T
   802  		{[]interface{}{"a", "b", "c", "c"}, []string{"a", "b", "d"}, []interface{}{"a", "b", "c", "d"}, false},
   803  		{[]interface{}{}, []string{}, []interface{}{}, false},
   804  		{[]interface{}{1, 2}, []int{2, 3}, []interface{}{1, 2, 3}, false},
   805  		{[]interface{}{1, 2}, []int8{2, 3}, []interface{}{1, 2, 3}, false}, // 28
   806  		{[]interface{}{uint(1), uint(2)}, []uint{2, 3}, []interface{}{uint(1), uint(2), uint(3)}, false},
   807  		{[]interface{}{1.1, 2.2}, []float64{2.2, 3.3}, []interface{}{1.1, 2.2, 3.3}, false},
   808  
   809  		// Structs
   810  		{pagesPtr{p1, p4}, pagesPtr{p4, p2, p2}, pagesPtr{p1, p4, p2}, false},
   811  		{pagesVals{p1v}, pagesVals{p3v, p3v}, pagesVals{p1v, p3v}, false},
   812  		{[]interface{}{p1, p4}, []interface{}{p4, p2, p2}, []interface{}{p1, p4, p2}, false},
   813  		{[]interface{}{p1v}, []interface{}{p3v, p3v}, []interface{}{p1v, p3v}, false},
   814  		// #3686
   815  		{[]interface{}{p1v}, []interface{}{}, []interface{}{p1v}, false},
   816  		{[]interface{}{}, []interface{}{p1v}, []interface{}{p1v}, false},
   817  		{pagesPtr{p1}, pagesPtr{}, pagesPtr{p1}, false},
   818  		{pagesVals{p1v}, pagesVals{}, pagesVals{p1v}, false},
   819  		{pagesPtr{}, pagesPtr{p1}, pagesPtr{p1}, false},
   820  		{pagesVals{}, pagesVals{p1v}, pagesVals{p1v}, false},
   821  
   822  		// errors
   823  		{"not array or slice", []string{"a"}, false, true},
   824  		{[]string{"a"}, "not array or slice", false, true},
   825  
   826  		// uncomparable types - #3820
   827  		{[]map[string]int{{"K1": 1}}, []map[string]int{{"K2": 2}, {"K2": 2}}, false, true},
   828  		{[][]int{{1, 1}, {1, 2}}, [][]int{{2, 1}, {2, 2}}, false, true},
   829  	} {
   830  
   831  		errMsg := qt.Commentf("[%d] %v", i, test)
   832  
   833  		result, err := ns.Union(test.l1, test.l2)
   834  		if test.isErr {
   835  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   836  			continue
   837  		}
   838  
   839  		c.Assert(err, qt.IsNil, errMsg)
   840  		if !reflect.DeepEqual(result, test.expect) {
   841  			t.Fatalf("[%d] Got\n%v expected\n%v", i, result, test.expect)
   842  		}
   843  	}
   844  }
   845  
   846  func TestUniq(t *testing.T) {
   847  	t.Parallel()
   848  	c := qt.New(t)
   849  	ns := New(&deps.Deps{})
   850  	for i, test := range []struct {
   851  		l      interface{}
   852  		expect interface{}
   853  		isErr  bool
   854  	}{
   855  		{[]string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
   856  		{[]string{"a", "b", "c", "c"}, []string{"a", "b", "c"}, false},
   857  		{[]string{"a", "b", "b", "c"}, []string{"a", "b", "c"}, false},
   858  		{[]string{"a", "b", "c", "b"}, []string{"a", "b", "c"}, false},
   859  		{[]int{1, 2, 3}, []int{1, 2, 3}, false},
   860  		{[]int{1, 2, 3, 3}, []int{1, 2, 3}, false},
   861  		{[]int{1, 2, 2, 3}, []int{1, 2, 3}, false},
   862  		{[]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
   863  		{[4]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
   864  		{nil, make([]interface{}, 0), false},
   865  		// Pointers
   866  		{pagesPtr{p1, p2, p3, p2}, pagesPtr{p1, p2, p3}, false},
   867  		{pagesPtr{}, pagesPtr{}, false},
   868  		// Structs
   869  		{pagesVals{p3v, p2v, p3v, p2v}, pagesVals{p3v, p2v}, false},
   870  
   871  		// not Comparable(), use hashstructure
   872  		{[]map[string]int{
   873  			{"K1": 1}, {"K2": 2}, {"K1": 1}, {"K2": 1},
   874  		}, []map[string]int{
   875  			{"K1": 1}, {"K2": 2}, {"K2": 1},
   876  		}, false},
   877  
   878  		// should fail
   879  		{1, 1, true},
   880  		{"foo", "fo", true},
   881  	} {
   882  		errMsg := qt.Commentf("[%d] %v", i, test)
   883  
   884  		result, err := ns.Uniq(test.l)
   885  		if test.isErr {
   886  			c.Assert(err, qt.Not(qt.IsNil), errMsg)
   887  			continue
   888  		}
   889  
   890  		c.Assert(err, qt.IsNil, errMsg)
   891  		c.Assert(result, qt.DeepEquals, test.expect, errMsg)
   892  	}
   893  }
   894  
   895  func (x *TstX) TstRp() string {
   896  	return "r" + x.A
   897  }
   898  
   899  func (x TstX) TstRv() string {
   900  	return "r" + x.B
   901  }
   902  
   903  func (x TstX) TstRv2() string {
   904  	return "r" + x.B
   905  }
   906  
   907  func (x TstX) unexportedMethod() string {
   908  	return x.unexported
   909  }
   910  
   911  func (x TstX) MethodWithArg(s string) string {
   912  	return s
   913  }
   914  
   915  func (x TstX) MethodReturnNothing() {}
   916  
   917  func (x TstX) MethodReturnErrorOnly() error {
   918  	return errors.New("some error occurred")
   919  }
   920  
   921  func (x TstX) MethodReturnTwoValues() (string, string) {
   922  	return "foo", "bar"
   923  }
   924  
   925  func (x TstX) MethodReturnValueWithError() (string, error) {
   926  	return "", errors.New("some error occurred")
   927  }
   928  
   929  func (x TstX) String() string {
   930  	return fmt.Sprintf("A: %s, B: %s", x.A, x.B)
   931  }
   932  
   933  type TstX struct {
   934  	A, B       string
   935  	unexported string
   936  }
   937  
   938  type TstParams struct {
   939  	params maps.Params
   940  }
   941  
   942  func (x TstParams) Params() maps.Params {
   943  	return x.params
   944  }
   945  
   946  type TstXIHolder struct {
   947  	XI TstXI
   948  }
   949  
   950  // Partially implemented by the TstX struct.
   951  type TstXI interface {
   952  	TstRv2() string
   953  }
   954  
   955  func ToTstXIs(slice interface{}) []TstXI {
   956  	s := reflect.ValueOf(slice)
   957  	if s.Kind() != reflect.Slice {
   958  		return nil
   959  	}
   960  	tis := make([]TstXI, s.Len())
   961  
   962  	for i := 0; i < s.Len(); i++ {
   963  		tsti, ok := s.Index(i).Interface().(TstXI)
   964  		if !ok {
   965  			return nil
   966  		}
   967  		tis[i] = tsti
   968  	}
   969  
   970  	return tis
   971  }
   972  
   973  func newDeps(cfg config.Provider) *deps.Deps {
   974  	l := langs.NewLanguage("en", cfg)
   975  	l.Set("i18nDir", "i18n")
   976  	cs, err := helpers.NewContentSpec(l, loggers.NewErrorLogger(), afero.NewMemMapFs())
   977  	if err != nil {
   978  		panic(err)
   979  	}
   980  	return &deps.Deps{
   981  		Cfg:         cfg,
   982  		Fs:          hugofs.NewMem(l),
   983  		ContentSpec: cs,
   984  		Log:         loggers.NewErrorLogger(),
   985  	}
   986  }
   987  
   988  func newTestNs() *Namespace {
   989  	v := config.New()
   990  	v.Set("contentDir", "content")
   991  	return New(newDeps(v))
   992  }