shithub: hugo

Download patch

ref: 51cabe6fafe5b18ce27962b7ec469f69fd5e2229
parent: be44345272276264719ede32447ce62fa92aa508
author: Tatsushi Demachi <[email protected]>
date: Sat Jun 6 20:21:14 EDT 2015

Fix substr tpl func's int type variant issue

`substr` template function takes one or two range arguments. Both
arguments must be int type values but if it is used with a calclation
function e.g. `add`, `len` etc, it causes a wrong type error.

This fixes the issue to allow the function to take other integer type
variant like `int64` etc.

This also includes a small fix on no range argument case.

Fix #1190

--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -170,7 +170,7 @@
 // In addition, borrowing from the extended behavior described at http://php.net/substr,
 // if length is given and is negative, then that many characters will be omitted from
 // the end of string.
-func Substr(a interface{}, nums ...int) (string, error) {
+func Substr(a interface{}, nums ...interface{}) (string, error) {
 	aStr, err := cast.ToStringE(a)
 	if err != nil {
 		return "", err
@@ -177,13 +177,38 @@
 	}
 
 	var start, length int
+	toInt := func (v interface{}, message string) (int, error) {
+		switch i := v.(type) {
+		case int:
+			return i, nil
+		case int8:
+			return int(i), nil
+		case int16:
+			return int(i), nil
+		case int32:
+			return int(i), nil
+		case int64:
+			return int(i), nil
+		default:
+			return 0, errors.New(message)
+		}
+	}
+
 	switch len(nums) {
+	case 0:
+		return "", errors.New("too less arguments")
 	case 1:
-		start = nums[0]
+		if start, err = toInt(nums[0], "start argument must be integer"); err != nil {
+			return "", err
+		}
 		length = len(aStr)
 	case 2:
-		start = nums[0]
-		length = nums[1]
+		if start, err = toInt(nums[0], "start argument must be integer"); err != nil {
+			return "", err
+		}
+		if length, err = toInt(nums[1], "length argument must be integer"); err != nil {
+			return "", err
+		}
 	default:
 		return "", errors.New("too many arguments")
 	}
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -317,10 +317,12 @@
 }
 
 func TestSubstr(t *testing.T) {
+	var err error
+	var n int
 	for i, this := range []struct {
 		v1     interface{}
-		v2     int
-		v3     int
+		v2     interface{}
+		v3     interface{}
 		expect interface{}
 	}{
 		{"abc", 1, 2, "bc"},
@@ -334,12 +336,31 @@
 		{"abcdef", 1, 100, "bcdef"},
 		{"abcdef", -100, 3, "abc"},
 		{"abcdef", -3, -1, "de"},
+		{"abcdef", 2, nil, "cdef"},
+		{"abcdef", int8(2), nil, "cdef"},
+		{"abcdef", int16(2), nil, "cdef"},
+		{"abcdef", int32(2), nil, "cdef"},
+		{"abcdef", int64(2), nil, "cdef"},
+		{"abcdef", 2, int8(3), "cde"},
+		{"abcdef", 2, int16(3), "cde"},
+		{"abcdef", 2, int32(3), "cde"},
+		{"abcdef", 2, int64(3), "cde"},
 		{123, 1, 3, "23"},
 		{1.2e3, 0, 4, "1200"},
 		{tstNoStringer{}, 0, 1, false},
+		{"abcdef", 2.0, nil, false},
+		{"abcdef", 2.0, 2, false},
+		{"abcdef", 2, 2.0, false},
 	} {
-		result, err := Substr(this.v1, this.v2, this.v3)
+		var result string
+		n = i
 
+		if this.v3 == nil {
+			result, err = Substr(this.v1, this.v2)
+		} else {
+			result, err = Substr(this.v1, this.v2, this.v3)
+		}
+
 		if b, ok := this.expect.(bool); ok && !b {
 			if err == nil {
 				t.Errorf("[%d] Substr didn't return an expected error", i)
@@ -353,6 +374,18 @@
 				t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
 			}
 		}
+	}
+
+	n++
+	_, err = Substr("abcdef")
+	if err == nil {
+		t.Errorf("[%d] Substr didn't return an expected error", n)
+	}
+
+	n++
+	_, err = Substr("abcdef", 1, 2, 3)
+	if err == nil {
+		t.Errorf("[%d] Substr didn't return an expected error", n)
 	}
 }