Repository: gohugoio/hugo (language: go)

Issue:
The ne, lt, le, gt, and ge comparison operators should fail given a single argument
Prior to [`0c251be`](https://github.com/gohugoio/hugo/commit/0c251be66bf3ad4abafbc47583e394ca4e6ffcf1) ([#6775](https://github.com/gohugoio/hugo/pull/6775)) ...

```text
{{ if eq 42 }} foo {{ end }} --> error calling eq: missing arguments for comparison
{{ if ne 42 }} foo {{ end }} --> wrong number of args for ne: want 2 got 1
{{ if gt 42 }} foo {{ end }} --> wrong number of args for gt: want 2 got 1
{{ if ge 42 }} foo {{ end }} --> wrong number of args for ge: want 2 got 1
{{ if lt 42 }} foo {{ end }} --> wrong number of args for lt: want 2 got 1
{{ if le 42 }} foo {{ end }} --> wrong number of args for le: want 2 got 1
```

Currently:

```
{{ if eq 42 }} foo {{ end }} --> error calling eq: missing arguments for comparison 
{{ if ne 42 }} foo {{ end }} --> foo
{{ if gt 42 }} foo {{ end }} --> foo
{{ if ge 42 }} foo {{ end }} --> foo
{{ if lt 42 }} foo {{ end }} --> foo
{{ if le 42 }} foo {{ end }} --> foo
```

Fixing this will break some already broken things in the wild. What brought this to my attention was someone doing `ne .IsHome` instead of `not .IsHome`. 





Discussion / hints:

Fix patch:
diff --git a/tpl/compare/compare.go b/tpl/compare/compare.go
index 88b18f00cd4..8f3f536b58b 100644
--- a/tpl/compare/compare.go
+++ b/tpl/compare/compare.go
@@ -95,10 +95,7 @@ func (n *Namespace) Eq(first interface{}, others ...interface{}) bool {
 	if n.caseInsensitive {
 		panic("caseInsensitive not implemented for Eq")
 	}
-	if len(others) == 0 {
-		panic("missing arguments for comparison")
-	}
-
+	n.checkComparisonArgCount(1, others...)
 	normalize := func(v interface{}) interface{} {
 		if types.IsNil(v) {
 			return nil
@@ -145,6 +142,7 @@ func (n *Namespace) Eq(first interface{}, others ...interface{}) bool {
 
 // Ne returns the boolean truth of arg1 != arg2 && arg1 != arg3 && arg1 != arg4.
 func (n *Namespace) Ne(first interface{}, others ...interface{}) bool {
+	n.checkComparisonArgCount(1, others...)
 	for _, other := range others {
 		if n.Eq(first, other) {
 			return false
@@ -155,6 +153,7 @@ func (n *Namespace) Ne(first interface{}, others ...interface{}) bool {
 
 // Ge returns the boolean truth of arg1 >= arg2 && arg1 >= arg3 && arg1 >= arg4.
 func (n *Namespace) Ge(first interface{}, others ...interface{}) bool {
+	n.checkComparisonArgCount(1, others...)
 	for _, other := range others {
 		left, right := n.compareGet(first, other)
 		if !(left >= right) {
@@ -166,6 +165,7 @@ func (n *Namespace) Ge(first interface{}, others ...interface{}) bool {
 
 // Gt returns the boolean truth of arg1 > arg2 && arg1 > arg3 && arg1 > arg4.
 func (n *Namespace) Gt(first interface{}, others ...interface{}) bool {
+	n.checkComparisonArgCount(1, others...)
 	for _, other := range others {
 		left, right := n.compareGet(first, other)
 		if !(left > right) {
@@ -177,6 +177,7 @@ func (n *Namespace) Gt(first interface{}, others ...interface{}) bool {
 
 // Le returns the boolean truth of arg1 <= arg2 && arg1 <= arg3 && arg1 <= arg4.
 func (n *Namespace) Le(first interface{}, others ...interface{}) bool {
+	n.checkComparisonArgCount(1, others...)
 	for _, other := range others {
 		left, right := n.compareGet(first, other)
 		if !(left <= right) {
@@ -188,6 +189,7 @@ func (n *Namespace) Le(first interface{}, others ...interface{}) bool {
 
 // Lt returns the boolean truth of arg1 < arg2 && arg1 < arg3 && arg1 < arg4.
 func (n *Namespace) Lt(first interface{}, others ...interface{}) bool {
+	n.checkComparisonArgCount(1, others...)
 	for _, other := range others {
 		left, right := n.compareGet(first, other)
 		if !(left < right) {
@@ -197,6 +199,13 @@ func (n *Namespace) Lt(first interface{}, others ...interface{}) bool {
 	return true
 }
 
+func (n *Namespace) checkComparisonArgCount(min int, others ...interface{}) bool {
+	if len(others) < min {
+		panic("missing arguments for comparison")
+	}
+	return true
+}
+
 // Conditional can be used as a ternary operator.
 // It returns a if condition, else b.
 func (n *Namespace) Conditional(condition bool, a, b interface{}) interface{} {


Test patch:
diff --git a/tpl/compare/compare_test.go b/tpl/compare/compare_test.go
index 76fe2698a9f..9ef32fd851d 100644
--- a/tpl/compare/compare_test.go
+++ b/tpl/compare/compare_test.go
@@ -440,3 +440,20 @@ func TestConditional(t *testing.T) {
 	c.Assert(n.Conditional(true, a, b), qt.Equals, a)
 	c.Assert(n.Conditional(false, a, b), qt.Equals, b)
 }
+
+// Issue 9462
+func TestComparisonArgCount(t *testing.T) {
+	t.Parallel()
+	c := qt.New(t)
+
+	ns := New(false)
+
+	panicMsg := "missing arguments for comparison"
+
+	c.Assert(func() { ns.Eq(1) }, qt.PanicMatches, panicMsg)
+	c.Assert(func() { ns.Ge(1) }, qt.PanicMatches, panicMsg)
+	c.Assert(func() { ns.Gt(1) }, qt.PanicMatches, panicMsg)
+	c.Assert(func() { ns.Le(1) }, qt.PanicMatches, panicMsg)
+	c.Assert(func() { ns.Lt(1) }, qt.PanicMatches, panicMsg)
+	c.Assert(func() { ns.Ne(1) }, qt.PanicMatches, panicMsg)
+}