mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Rename random to shuffle. Remove count parameteter to simplify its role. Add tests for randomising.
This commit is contained in:
parent
302a6ac701
commit
9008ac0b55
2 changed files with 55 additions and 40 deletions
|
@ -496,24 +496,14 @@ func After(index interface{}, seq interface{}) (interface{}, error) {
|
||||||
return seqv.Slice(indexv, seqv.Len()).Interface(), nil
|
return seqv.Slice(indexv, seqv.Len()).Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Random is exposed to templates, to iterate over N random items in a
|
// Shuffle is exposed to templates, to iterate over items in rangeable list in
|
||||||
// rangeable list.
|
// a randomised order.
|
||||||
func Random(count interface{}, seq interface{}) (interface{}, error) {
|
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")
|
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 := reflect.ValueOf(seq)
|
||||||
seqv, isNil := indirect(seqv)
|
seqv, isNil := indirect(seqv)
|
||||||
if isNil {
|
if isNil {
|
||||||
|
@ -527,20 +517,16 @@ func Random(count interface{}, seq interface{}) (interface{}, error) {
|
||||||
return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
|
return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if countv >= seqv.Len() {
|
shuffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
|
||||||
countv = seqv.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
suffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UTC().UnixNano())
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
randomIndices := rand.Perm(seqv.Len())
|
randomIndices := rand.Perm(seqv.Len())
|
||||||
|
|
||||||
for index, value := range randomIndices {
|
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 (
|
var (
|
||||||
|
@ -1501,7 +1487,7 @@ func init() {
|
||||||
"first": First,
|
"first": First,
|
||||||
"last": Last,
|
"last": Last,
|
||||||
"after": After,
|
"after": After,
|
||||||
"random": Random,
|
"shuffle": Shuffle,
|
||||||
"where": Where,
|
"where": Where,
|
||||||
"delimit": Delimit,
|
"delimit": Delimit,
|
||||||
"sort": Sort,
|
"sort": Sort,
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -341,43 +342,71 @@ func TestAfter(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRandom(t *testing.T) {
|
func TestShuffleInputAndOutputFormat(t *testing.T) {
|
||||||
for i, this := range []struct {
|
for i, this := range []struct {
|
||||||
count interface{}
|
|
||||||
sequence interface{}
|
sequence interface{}
|
||||||
expect interface{}
|
success bool
|
||||||
}{
|
}{
|
||||||
{int(2), []string{"a", "b", "c", "d"}, 2},
|
{[]string{"a", "b", "c", "d"}, true},
|
||||||
{int64(2), []int{100, 200, 300}, 2},
|
{[]int{100, 200, 300}, true},
|
||||||
{"1", []int{100, 200, 300}, 1},
|
{[]int{100, 200, 300}, true},
|
||||||
{100, []int{100, 200}, 2},
|
{[]int{100, 200}, true},
|
||||||
{int32(3), []string{"a", "b"}, 2},
|
{[]string{"a", "b"}, true},
|
||||||
{int64(-1), []int{100, 200, 300}, false},
|
{[]int{100, 200, 300}, true},
|
||||||
{"noint", []int{100, 200, 300}, false},
|
{[]int{100, 200, 300}, true},
|
||||||
{1, nil, false},
|
{[]int{100}, true},
|
||||||
{nil, []int{100}, false},
|
{nil, false},
|
||||||
{1, t, false},
|
{t, false},
|
||||||
} {
|
} {
|
||||||
results, err := Random(this.count, this.sequence)
|
results, err := Shuffle(this.sequence)
|
||||||
if b, ok := this.expect.(bool); ok && !b {
|
if !this.success {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("[%d] First didn't return an expected error", i)
|
t.Errorf("[%d] First didn't return an expected error", i)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultsv := reflect.ValueOf(results)
|
resultsv := reflect.ValueOf(results)
|
||||||
|
sequencev := reflect.ValueOf(this.sequence)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("[%d] failed: %s", i, err)
|
t.Errorf("[%d] failed: %s", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if resultsv.Len() != this.expect {
|
if resultsv.Len() != sequencev.Len() {
|
||||||
t.Errorf("[%d] requested %d random items, got %v but expected %v",
|
t.Errorf("Expected %d items, got %d items", sequencev.Len(), resultsv.Len())
|
||||||
i, this.count, resultsv.Len(), this.expect)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestDictionary(t *testing.T) {
|
||||||
for i, this := range []struct {
|
for i, this := range []struct {
|
||||||
v1 []interface{}
|
v1 []interface{}
|
||||||
|
|
Loading…
Reference in a new issue