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