]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
tpl/collections: Add an integration test for collections.D
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 27 Aug 2025 13:21:29 +0000 (15:21 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 27 Aug 2025 15:25:05 +0000 (17:25 +0200)
Also
* improve the handling if invalid input
* add a sanity check for number of elements asked for in D (1000000).

tpl/collections/collections.go
tpl/collections/collections_integration_test.go
tpl/collections/collections_test.go

index 5d2fc86e9f18a0805d47288eafb26b06a6e03dea..1447a3fab6659bfd59c59f6b12385d2c69621643 100644 (file)
@@ -409,6 +409,11 @@ func (ns *Namespace) Reverse(l any) (any, error) {
        return sliceCopy.Interface(), nil
 }
 
+// Sanity check for slices created by Seq and D.
+const maxSeqSize = 1000000
+
+var errSeqSizeExceedsLimit = errors.New("size of result exceeds limit")
+
 // Seq creates a sequence of integers from args. It's named and used as GNU's seq.
 //
 // Examples:
@@ -462,14 +467,14 @@ func (ns *Namespace) Seq(args ...any) ([]int, error) {
        }
 
        // sanity check
-       if last < -100000 {
-               return nil, errors.New("size of result exceeds limit")
+       if last < -maxSeqSize {
+               return nil, errSeqSizeExceedsLimit
        }
        size := ((last - first) / inc) + 1
 
        // sanity check
-       if size <= 0 || size > 2000 {
-               return nil, errors.New("size of result exceeds limit")
+       if size <= 0 || size > maxSeqSize {
+               return nil, errSeqSizeExceedsLimit
        }
 
        seq := make([]int, size)
@@ -536,6 +541,12 @@ type dKey struct {
 // See  https://getkerf.wordpress.com/2016/03/30/the-best-algorithm-no-one-knows-about/
 func (ns *Namespace) D(seed, n, hi any) []int {
        key := dKey{seed: cast.ToUint64(seed), n: cast.ToInt(n), hi: cast.ToInt(hi)}
+       if key.n <= 0 || key.hi <= 0 || key.n > key.hi {
+               return nil
+       }
+       if key.n > maxSeqSize {
+               panic(errSeqSizeExceedsLimit)
+       }
        v, _ := ns.dCache.GetOrCreate(key, func() ([]int, error) {
                prng := rand.New(rand.NewPCG(key.seed, 0))
                result := make([]int, 0, key.n)
index b60aaea87b086d39c8c383ae8e7e14b9e51739b9..84af4153dd9f232116920728637ae9500c138669 100644 (file)
@@ -298,3 +298,33 @@ All|{{ .Title }}|
 
        b.AssertFileContent("public/index.html", "Len: 1|")
 }
+
+func TestD(t *testing.T) {
+       t.Parallel()
+       files := `
+-- hugo.toml --
+-- layouts/home.html --
+{{ $p := site.RegularPages }}
+5 random pages: {{ range collections.D 42 5 ($p | len) }}{{ with (index $p .) }}{{ .RelPermalink }}|{{ end }}{{ end }}$
+-- content/a.md --
+-- content/b.md --
+-- content/c.md --
+-- content/d.md --
+-- content/e.md --
+-- content/f.md --
+-- content/g.md --
+-- content/h.md --
+-- content/i.md --
+-- content/j.md --
+-- content/k.md --
+-- content/l.md --
+-- content/m.md --
+-- content/n.md --
+-- content/o.md --
+-- content/p.md --
+
+`
+       b := hugolib.Test(t, files)
+
+       b.AssertFileContentExact("public/index.html", "5 random pages: /b/|/g/|/j/|/k/|/l/|$")
+}
index 0e2d99224342a60ff50d6c993df83bcffdc41cdd..0face752c06bd561074748307d95c5b220a0a7ad 100644 (file)
@@ -536,7 +536,7 @@ func TestSeq(t *testing.T) {
                {[]any{1, -1, 2}, false},
                {[]any{2, 1, 1}, false},
                {[]any{2, 1, 1, 1}, false},
-               {[]any{2001}, false},
+               {[]any{-1000001}, false},
                {[]any{}, false},
                {[]any{0, -1000000}, false},
                {[]any{tstNoStringer{}}, false},
@@ -795,6 +795,15 @@ func TestD(t *testing.T) {
 
        c.Assert(ns.D(42, 5, 100), qt.DeepEquals, []int{24, 34, 66, 82, 96})
        c.Assert(ns.D(31, 5, 100), qt.DeepEquals, []int{12, 37, 38, 69, 98})
+       c.Assert(ns.D(42, 9, 10), qt.DeepEquals, []int{0, 1, 2, 3, 4, 6, 7, 8, 9})
+       c.Assert(ns.D(42, 10, 10), qt.DeepEquals, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
+       c.Assert(ns.D(42, 11, 10), qt.IsNil) // n > hi
+       c.Assert(ns.D(42, -5, 100), qt.IsNil)
+       c.Assert(ns.D(42, 0, 100), qt.IsNil)
+       c.Assert(ns.D(42, 5, 0), qt.IsNil)
+       c.Assert(ns.D(42, 5, -10), qt.IsNil)
+       c.Assert(ns.D(42, 5, 3000000), qt.DeepEquals, []int{720363, 1041693, 2009179, 2489106, 2873969})
+       c.Assert(func() { ns.D(31, 2000000, 3000000) }, qt.PanicMatches, "size of result exceeds limit")
 }
 
 func BenchmarkD2(b *testing.B) {