shithub: hugo

Download patch

ref: 9008ac0b55bc0f507e730e8b3d49fa8103e600e1
parent: 302a6ac701bc2599d4ca98c7d263d364505a3980
author: Antti Järvinen <[email protected]>
date: Mon Dec 7 02:27:37 EST 2015

Rename random to shuffle. Remove count parameteter to simplify its role. Add tests for randomising.

--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -496,24 +496,14 @@
 	return seqv.Slice(indexv, seqv.Len()).Interface(), nil
 }
 
-// Random is exposed to templates, to iterate over N random items in a
-// rangeable list.
-func Random(count interface{}, seq interface{}) (interface{}, error) {
+// Shuffle is exposed to templates, to iterate over items in rangeable list in
+// a randomised order.
+func Shuffle(seq interface{}) (interface{}, error) {
 
-	if count == nil || seq == nil {
+	if seq == nil {
 		return nil, errors.New("both count and seq must be provided")
 	}
 
-	countv, err := cast.ToIntE(count)
-
-	if err != nil {
-		return nil, err
-	}
-
-	if countv < 1 {
-		return nil, errors.New("can't return negative/empty count of items from sequence")
-	}
-
 	seqv := reflect.ValueOf(seq)
 	seqv, isNil := indirect(seqv)
 	if isNil {
@@ -527,20 +517,16 @@
 		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
 	}
 
-	if countv >= seqv.Len() {
-		countv = seqv.Len()
-	}
+	shuffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
 
-	suffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
-
 	rand.Seed(time.Now().UTC().UnixNano())
 	randomIndices := rand.Perm(seqv.Len())
 
 	for index, value := range randomIndices {
-		suffled.Index(value).Set(seqv.Index(index))
+		shuffled.Index(value).Set(seqv.Index(index))
 	}
 
-	return suffled.Slice(0, countv).Interface(), nil
+	return shuffled.Interface(), nil
 }
 
 var (
@@ -1501,7 +1487,7 @@
 		"first":        First,
 		"last":         Last,
 		"after":        After,
-		"random":       Random,
+		"shuffle":      Shuffle,
 		"where":        Where,
 		"delimit":      Delimit,
 		"sort":         Sort,
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -25,6 +25,7 @@
 	"runtime"
 	"testing"
 	"time"
+	"math/rand"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -341,42 +342,70 @@
 	}
 }
 
-func TestRandom(t *testing.T) {
+func TestShuffleInputAndOutputFormat(t *testing.T) {
 	for i, this := range []struct {
-		count    interface{}
 		sequence interface{}
-		expect   interface{}
+		success bool
 	}{
-		{int(2), []string{"a", "b", "c", "d"}, 2},
-		{int64(2), []int{100, 200, 300}, 2},
-		{"1", []int{100, 200, 300}, 1},
-		{100, []int{100, 200}, 2},
-		{int32(3), []string{"a", "b"}, 2},
-		{int64(-1), []int{100, 200, 300}, false},
-		{"noint", []int{100, 200, 300}, false},
-		{1, nil, false},
-		{nil, []int{100}, false},
-		{1, t, false},
+		{[]string{"a", "b", "c", "d"}, true},
+		{[]int{100, 200, 300}, true},
+		{[]int{100, 200, 300}, true},
+		{[]int{100, 200}, true},
+		{[]string{"a", "b"}, true},
+		{[]int{100, 200, 300}, true},
+		{[]int{100, 200, 300}, true},
+		{[]int{100}, true},
+		{nil, false},
+		{t, false},
 	} {
-		results, err := Random(this.count, this.sequence)
-		if b, ok := this.expect.(bool); ok && !b {
+		results, err := Shuffle(this.sequence)
+		if !this.success {
 			if err == nil {
 				t.Errorf("[%d] First didn't return an expected error", i)
 			}
 		} else {
 			resultsv := reflect.ValueOf(results)
+			sequencev := reflect.ValueOf(this.sequence)
+
 			if err != nil {
 				t.Errorf("[%d] failed: %s", i, err)
 				continue
 			}
 
-			if resultsv.Len() != this.expect {
-				t.Errorf("[%d] requested %d random items, got %v but expected %v",
-					i, this.count, resultsv.Len(), this.expect)
+			if resultsv.Len() != sequencev.Len() {
+				t.Errorf("Expected %d items, got %d items", sequencev.Len(), resultsv.Len())
 			}
 		}
 	}
 }
+
+func TestShuffleRandomising(t *testing.T) {
+	// Note that this test can fail with false negative result if the shuffle
+	// of the sequence happens to be the same as the original sequence. However
+	// the propability of the event is 10^-158 which is negligible.
+	sequenceLength := 100
+	rand.Seed(time.Now().UTC().UnixNano())
+
+	for _, this := range []struct {
+		sequence []int
+	}{
+		{rand.Perm(sequenceLength)},
+	} {
+		results, _ := Shuffle(this.sequence)
+
+		resultsv := reflect.ValueOf(results)
+
+		allSame := true
+		for index, value := range this.sequence {
+			allSame = allSame && (resultsv.Index(index).Interface() == value)
+		}
+
+		if allSame {
+			t.Error("Expected sequence to be shuffled but was in the same order")
+		}
+	}
+}
+
 
 func TestDictionary(t *testing.T) {
 	for i, this := range []struct {