github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/tpl/compare/compare_test.go (about)

     1  // Copyright 2017 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 compare
    15  
    16  import (
    17  	"path"
    18  	"reflect"
    19  	"runtime"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/gohugoio/hugo/htesting/hqt"
    24  
    25  	qt "github.com/frankban/quicktest"
    26  	"github.com/gohugoio/hugo/common/hugo"
    27  	"github.com/spf13/cast"
    28  )
    29  
    30  type T struct {
    31  	NonEmptyInterfaceNil      I
    32  	NonEmptyInterfaceTypedNil I
    33  }
    34  
    35  type I interface {
    36  	Foo() string
    37  }
    38  
    39  func (t *T) Foo() string {
    40  	return "foo"
    41  }
    42  
    43  var testT = &T{
    44  	NonEmptyInterfaceTypedNil: (*T)(nil),
    45  }
    46  
    47  type (
    48  	tstEqerType1 string
    49  	tstEqerType2 string
    50  )
    51  
    52  func (t tstEqerType2) Eq(other interface{}) bool {
    53  	return cast.ToString(t) == cast.ToString(other)
    54  }
    55  
    56  func (t tstEqerType2) String() string {
    57  	return string(t)
    58  }
    59  
    60  func (t tstEqerType1) Eq(other interface{}) bool {
    61  	return cast.ToString(t) == cast.ToString(other)
    62  }
    63  
    64  func (t tstEqerType1) String() string {
    65  	return string(t)
    66  }
    67  
    68  type stringType string
    69  
    70  type tstCompareType int
    71  
    72  const (
    73  	tstEq tstCompareType = iota
    74  	tstNe
    75  	tstGt
    76  	tstGe
    77  	tstLt
    78  	tstLe
    79  )
    80  
    81  func tstIsEq(tp tstCompareType) bool { return tp == tstEq || tp == tstGe || tp == tstLe }
    82  func tstIsGt(tp tstCompareType) bool { return tp == tstGt || tp == tstGe }
    83  func tstIsLt(tp tstCompareType) bool { return tp == tstLt || tp == tstLe }
    84  
    85  func TestDefaultFunc(t *testing.T) {
    86  	t.Parallel()
    87  	c := qt.New(t)
    88  
    89  	then := time.Now()
    90  	now := time.Now()
    91  	ns := New(false)
    92  
    93  	for i, test := range []struct {
    94  		dflt   interface{}
    95  		given  interface{}
    96  		expect interface{}
    97  	}{
    98  		{true, false, false},
    99  		{"5", 0, "5"},
   100  
   101  		{"test1", "set", "set"},
   102  		{"test2", "", "test2"},
   103  		{"test3", nil, "test3"},
   104  
   105  		{[2]int{10, 20}, [2]int{1, 2}, [2]int{1, 2}},
   106  		{[2]int{10, 20}, [0]int{}, [2]int{10, 20}},
   107  		{[2]int{100, 200}, nil, [2]int{100, 200}},
   108  
   109  		{[]string{"one"}, []string{"uno"}, []string{"uno"}},
   110  		{[]string{"two"}, []string{}, []string{"two"}},
   111  		{[]string{"three"}, nil, []string{"three"}},
   112  
   113  		{map[string]int{"one": 1}, map[string]int{"uno": 1}, map[string]int{"uno": 1}},
   114  		{map[string]int{"one": 1}, map[string]int{}, map[string]int{"one": 1}},
   115  		{map[string]int{"two": 2}, nil, map[string]int{"two": 2}},
   116  
   117  		{10, 1, 1},
   118  		{10, 0, 10},
   119  		{20, nil, 20},
   120  
   121  		{float32(10), float32(1), float32(1)},
   122  		{float32(10), 0, float32(10)},
   123  		{float32(20), nil, float32(20)},
   124  
   125  		{complex(2, -2), complex(1, -1), complex(1, -1)},
   126  		{complex(2, -2), complex(0, 0), complex(2, -2)},
   127  		{complex(3, -3), nil, complex(3, -3)},
   128  
   129  		{struct{ f string }{f: "one"}, struct{}{}, struct{}{}},
   130  		{struct{ f string }{f: "two"}, nil, struct{ f string }{f: "two"}},
   131  
   132  		{then, now, now},
   133  		{then, time.Time{}, then},
   134  	} {
   135  
   136  		eq := qt.CmpEquals(hqt.DeepAllowUnexported(test.dflt))
   137  
   138  		errMsg := qt.Commentf("[%d] %v", i, test)
   139  
   140  		result, err := ns.Default(test.dflt, test.given)
   141  
   142  		c.Assert(err, qt.IsNil, errMsg)
   143  		c.Assert(result, eq, test.expect, errMsg)
   144  	}
   145  }
   146  
   147  func TestCompare(t *testing.T) {
   148  	t.Parallel()
   149  
   150  	n := New(false)
   151  
   152  	twoEq := func(a, b interface{}) bool {
   153  		return n.Eq(a, b)
   154  	}
   155  
   156  	twoGt := func(a, b interface{}) bool {
   157  		return n.Gt(a, b)
   158  	}
   159  
   160  	twoLt := func(a, b interface{}) bool {
   161  		return n.Lt(a, b)
   162  	}
   163  
   164  	twoGe := func(a, b interface{}) bool {
   165  		return n.Ge(a, b)
   166  	}
   167  
   168  	twoLe := func(a, b interface{}) bool {
   169  		return n.Le(a, b)
   170  	}
   171  
   172  	twoNe := func(a, b interface{}) bool {
   173  		return n.Ne(a, b)
   174  	}
   175  
   176  	for _, test := range []struct {
   177  		tstCompareType
   178  		funcUnderTest func(a, b interface{}) bool
   179  	}{
   180  		{tstGt, twoGt},
   181  		{tstLt, twoLt},
   182  		{tstGe, twoGe},
   183  		{tstLe, twoLe},
   184  		{tstEq, twoEq},
   185  		{tstNe, twoNe},
   186  	} {
   187  		doTestCompare(t, test.tstCompareType, test.funcUnderTest)
   188  	}
   189  }
   190  
   191  func doTestCompare(t *testing.T, tp tstCompareType, funcUnderTest func(a, b interface{}) bool) {
   192  	for i, test := range []struct {
   193  		left            interface{}
   194  		right           interface{}
   195  		expectIndicator int
   196  	}{
   197  		{5, 8, -1},
   198  		{8, 5, 1},
   199  		{5, 5, 0},
   200  		{int(5), int64(5), 0},
   201  		{int32(5), int(5), 0},
   202  		{int16(4), int(5), -1},
   203  		{uint(15), uint64(15), 0},
   204  		{-2, 1, -1},
   205  		{2, -5, 1},
   206  		{0.0, 1.23, -1},
   207  		{1.1, 1.1, 0},
   208  		{float32(1.0), float64(1.0), 0},
   209  		{1.23, 0.0, 1},
   210  		{"5", "5", 0},
   211  		{"8", "5", 1},
   212  		{"5", "0001", 1},
   213  		{[]int{100, 99}, []int{1, 2, 3, 4}, -1},
   214  		{cast.ToTime("2015-11-20"), cast.ToTime("2015-11-20"), 0},
   215  		{cast.ToTime("2015-11-19"), cast.ToTime("2015-11-20"), -1},
   216  		{cast.ToTime("2015-11-20"), cast.ToTime("2015-11-19"), 1},
   217  		{"a", "a", 0},
   218  		{"a", "b", -1},
   219  		{"b", "a", 1},
   220  		{tstEqerType1("a"), tstEqerType1("a"), 0},
   221  		{tstEqerType1("a"), tstEqerType2("a"), 0},
   222  		{tstEqerType2("a"), tstEqerType1("a"), 0},
   223  		{tstEqerType2("a"), tstEqerType1("b"), -1},
   224  		{hugo.MustParseVersion("0.32.1").Version(), hugo.MustParseVersion("0.32").Version(), 1},
   225  		{hugo.MustParseVersion("0.35").Version(), hugo.MustParseVersion("0.32").Version(), 1},
   226  		{hugo.MustParseVersion("0.36").Version(), hugo.MustParseVersion("0.36").Version(), 0},
   227  		{hugo.MustParseVersion("0.32").Version(), hugo.MustParseVersion("0.36").Version(), -1},
   228  		{hugo.MustParseVersion("0.32").Version(), "0.36", -1},
   229  		{"0.36", hugo.MustParseVersion("0.32").Version(), 1},
   230  		{"0.36", hugo.MustParseVersion("0.36").Version(), 0},
   231  		{"0.37", hugo.MustParseVersion("0.37-DEV").Version(), 1},
   232  		{"0.37-DEV", hugo.MustParseVersion("0.37").Version(), -1},
   233  		{"0.36", hugo.MustParseVersion("0.37-DEV").Version(), -1},
   234  		{"0.37-DEV", hugo.MustParseVersion("0.37-DEV").Version(), 0},
   235  		// https://github.com/gohugoio/hugo/issues/5905
   236  		{nil, nil, 0},
   237  		{testT.NonEmptyInterfaceNil, nil, 0},
   238  		{testT.NonEmptyInterfaceTypedNil, nil, 0},
   239  	} {
   240  
   241  		result := funcUnderTest(test.left, test.right)
   242  		success := false
   243  
   244  		if test.expectIndicator == 0 {
   245  			if tstIsEq(tp) {
   246  				success = result
   247  			} else {
   248  				success = !result
   249  			}
   250  		}
   251  
   252  		if test.expectIndicator < 0 {
   253  			success = result && (tstIsLt(tp) || tp == tstNe)
   254  			success = success || (!result && !tstIsLt(tp))
   255  		}
   256  
   257  		if test.expectIndicator > 0 {
   258  			success = result && (tstIsGt(tp) || tp == tstNe)
   259  			success = success || (!result && (!tstIsGt(tp) || tp != tstNe))
   260  		}
   261  
   262  		if !success {
   263  			t.Fatalf("[%d][%s] %v compared to %v: %t", i, path.Base(runtime.FuncForPC(reflect.ValueOf(funcUnderTest).Pointer()).Name()), test.left, test.right, result)
   264  		}
   265  	}
   266  }
   267  
   268  func TestEqualExtend(t *testing.T) {
   269  	t.Parallel()
   270  	c := qt.New(t)
   271  
   272  	ns := New(false)
   273  
   274  	for _, test := range []struct {
   275  		first  interface{}
   276  		others []interface{}
   277  		expect bool
   278  	}{
   279  		{1, []interface{}{1, 2}, true},
   280  		{1, []interface{}{2, 1}, true},
   281  		{1, []interface{}{2, 3}, false},
   282  		{tstEqerType1("a"), []interface{}{tstEqerType1("a"), tstEqerType1("b")}, true},
   283  		{tstEqerType1("a"), []interface{}{tstEqerType1("b"), tstEqerType1("a")}, true},
   284  		{tstEqerType1("a"), []interface{}{tstEqerType1("b"), tstEqerType1("c")}, false},
   285  	} {
   286  
   287  		result := ns.Eq(test.first, test.others...)
   288  
   289  		c.Assert(result, qt.Equals, test.expect)
   290  	}
   291  }
   292  
   293  func TestNotEqualExtend(t *testing.T) {
   294  	t.Parallel()
   295  	c := qt.New(t)
   296  
   297  	ns := New(false)
   298  
   299  	for _, test := range []struct {
   300  		first  interface{}
   301  		others []interface{}
   302  		expect bool
   303  	}{
   304  		{1, []interface{}{2, 3}, true},
   305  		{1, []interface{}{2, 1}, false},
   306  		{1, []interface{}{1, 2}, false},
   307  	} {
   308  		result := ns.Ne(test.first, test.others...)
   309  		c.Assert(result, qt.Equals, test.expect)
   310  	}
   311  }
   312  
   313  func TestGreaterEqualExtend(t *testing.T) {
   314  	t.Parallel()
   315  	c := qt.New(t)
   316  
   317  	ns := New(false)
   318  
   319  	for _, test := range []struct {
   320  		first  interface{}
   321  		others []interface{}
   322  		expect bool
   323  	}{
   324  		{5, []interface{}{2, 3}, true},
   325  		{5, []interface{}{5, 5}, true},
   326  		{3, []interface{}{4, 2}, false},
   327  		{3, []interface{}{2, 4}, false},
   328  	} {
   329  		result := ns.Ge(test.first, test.others...)
   330  		c.Assert(result, qt.Equals, test.expect)
   331  	}
   332  }
   333  
   334  func TestGreaterThanExtend(t *testing.T) {
   335  	t.Parallel()
   336  	c := qt.New(t)
   337  
   338  	ns := New(false)
   339  
   340  	for _, test := range []struct {
   341  		first  interface{}
   342  		others []interface{}
   343  		expect bool
   344  	}{
   345  		{5, []interface{}{2, 3}, true},
   346  		{5, []interface{}{5, 4}, false},
   347  		{3, []interface{}{4, 2}, false},
   348  	} {
   349  		result := ns.Gt(test.first, test.others...)
   350  		c.Assert(result, qt.Equals, test.expect)
   351  	}
   352  }
   353  
   354  func TestLessEqualExtend(t *testing.T) {
   355  	t.Parallel()
   356  	c := qt.New(t)
   357  
   358  	ns := New(false)
   359  
   360  	for _, test := range []struct {
   361  		first  interface{}
   362  		others []interface{}
   363  		expect bool
   364  	}{
   365  		{1, []interface{}{2, 3}, true},
   366  		{1, []interface{}{1, 2}, true},
   367  		{2, []interface{}{1, 2}, false},
   368  		{3, []interface{}{2, 4}, false},
   369  	} {
   370  		result := ns.Le(test.first, test.others...)
   371  		c.Assert(result, qt.Equals, test.expect)
   372  	}
   373  }
   374  
   375  func TestLessThanExtend(t *testing.T) {
   376  	t.Parallel()
   377  	c := qt.New(t)
   378  
   379  	ns := New(false)
   380  
   381  	for _, test := range []struct {
   382  		first  interface{}
   383  		others []interface{}
   384  		expect bool
   385  	}{
   386  		{1, []interface{}{2, 3}, true},
   387  		{1, []interface{}{1, 2}, false},
   388  		{2, []interface{}{1, 2}, false},
   389  		{3, []interface{}{2, 4}, false},
   390  	} {
   391  		result := ns.Lt(test.first, test.others...)
   392  		c.Assert(result, qt.Equals, test.expect)
   393  	}
   394  }
   395  
   396  func TestCase(t *testing.T) {
   397  	c := qt.New(t)
   398  	n := New(false)
   399  
   400  	c.Assert(n.Eq("az", "az"), qt.Equals, true)
   401  	c.Assert(n.Eq("az", stringType("az")), qt.Equals, true)
   402  }
   403  
   404  func TestStringType(t *testing.T) {
   405  	c := qt.New(t)
   406  	n := New(true)
   407  
   408  	c.Assert(n.Lt("az", "Za"), qt.Equals, true)
   409  	c.Assert(n.Gt("ab", "Ab"), qt.Equals, true)
   410  }
   411  
   412  func TestTimeUnix(t *testing.T) {
   413  	t.Parallel()
   414  	var sec int64 = 1234567890
   415  	tv := reflect.ValueOf(time.Unix(sec, 0))
   416  	i := 1
   417  
   418  	res := toTimeUnix(tv)
   419  	if sec != res {
   420  		t.Errorf("[%d] timeUnix got %v but expected %v", i, res, sec)
   421  	}
   422  
   423  	i++
   424  	func(t *testing.T) {
   425  		defer func() {
   426  			if err := recover(); err == nil {
   427  				t.Errorf("[%d] timeUnix didn't return an expected error", i)
   428  			}
   429  		}()
   430  		iv := reflect.ValueOf(sec)
   431  		toTimeUnix(iv)
   432  	}(t)
   433  }
   434  
   435  func TestConditional(t *testing.T) {
   436  	c := qt.New(t)
   437  	n := New(false)
   438  	a, b := "a", "b"
   439  
   440  	c.Assert(n.Conditional(true, a, b), qt.Equals, a)
   441  	c.Assert(n.Conditional(false, a, b), qt.Equals, b)
   442  }
   443  
   444  // Issue 9462
   445  func TestComparisonArgCount(t *testing.T) {
   446  	t.Parallel()
   447  	c := qt.New(t)
   448  
   449  	ns := New(false)
   450  
   451  	panicMsg := "missing arguments for comparison"
   452  
   453  	c.Assert(func() { ns.Eq(1) }, qt.PanicMatches, panicMsg)
   454  	c.Assert(func() { ns.Ge(1) }, qt.PanicMatches, panicMsg)
   455  	c.Assert(func() { ns.Gt(1) }, qt.PanicMatches, panicMsg)
   456  	c.Assert(func() { ns.Le(1) }, qt.PanicMatches, panicMsg)
   457  	c.Assert(func() { ns.Lt(1) }, qt.PanicMatches, panicMsg)
   458  	c.Assert(func() { ns.Ne(1) }, qt.PanicMatches, panicMsg)
   459  }