From b40f3c7df6bc89efaaadddec7d2cc291557b2ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Fri, 15 Mar 2024 13:12:25 +0100 Subject: [PATCH] Fix intersect and similar for term entry page collections Fixes #12254 --- common/types/types.go | 8 ++++ hugolib/page.go | 7 +++ tpl/collections/collections.go | 8 ++-- .../collections_integration_test.go | 48 +++++++++++++++++++ tpl/collections/reflect_helpers.go | 3 +- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/common/types/types.go b/common/types/types.go index 801c511a0..e3850ddac 100644 --- a/common/types/types.go +++ b/common/types/types.go @@ -99,6 +99,14 @@ type Unwrapper interface { Unwrapv() any } +// Unwrap returns the underlying value of v if it implements Unwrapper, otherwise v is returned. +func Unwrapv(v any) any { + if u, ok := v.(Unwrapper); ok { + return u.Unwrapv() + } + return v +} + // LowHigh is typically used to represent a slice boundary. type LowHigh struct { Low int diff --git a/hugolib/page.go b/hugolib/page.go index c743d4282..0622a15fe 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -36,6 +36,7 @@ import ( "github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/common/maps" + "github.com/gohugoio/hugo/common/types" "github.com/gohugoio/hugo/source" @@ -731,3 +732,9 @@ func (p pageWithWeight0) Weight0() int { func (p pageWithWeight0) page() page.Page { return p.pageState } + +var _ types.Unwrapper = (*pageWithWeight0)(nil) + +func (p pageWithWeight0) Unwrapv() any { + return p.pageState +} diff --git a/tpl/collections/collections.go b/tpl/collections/collections.go index 2107cf5a0..edec536ef 100644 --- a/tpl/collections/collections.go +++ b/tpl/collections/collections.go @@ -617,10 +617,10 @@ type intersector struct { } func (i *intersector) appendIfNotSeen(v reflect.Value) { - vi := v.Interface() - if !i.seen[vi] { + k := normalize(v) + if !i.seen[k] { i.r = reflect.Append(i.r, v) - i.seen[vi] = true + i.seen[k] = true } } @@ -638,7 +638,7 @@ func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) { i.appendIfNotSeen(l1vv) } case kind == reflect.Ptr, kind == reflect.Struct: - if l1vv.Interface() == l2vv.Interface() { + if types.Unwrapv(l1vv.Interface()) == types.Unwrapv(l2vv.Interface()) { i.appendIfNotSeen(l1vv) } case kind == reflect.Interface: diff --git a/tpl/collections/collections_integration_test.go b/tpl/collections/collections_integration_test.go index 1bcabb447..3bcd4effb 100644 --- a/tpl/collections/collections_integration_test.go +++ b/tpl/collections/collections_integration_test.go @@ -230,3 +230,51 @@ boolf = false "false", ) } + +func TestTermEntriesCollectionsIssue12254(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +capitalizeListTitles = false +disableKinds = ['rss','sitemap'] +-- content/p1.md -- +--- +title: p1 +categories: [cat-a] +tags: ['tag-b','tag-a','tag-c'] +--- +-- content/p2.md -- +--- +title: p2 +categories: [cat-a] +tags: ['tag-b','tag-a'] +--- +-- content/p3.md -- +--- +title: p3 +categories: [cat-a] +tags: ['tag-b'] +--- +-- layouts/_default/term.html -- +{{ $list1 := .Pages }} +{{ range $i, $e := site.Taxonomies.tags.ByCount }} +{{ $list2 := .Pages }} +{{ $i }}: List1: {{ len $list1 }}| +{{ $i }}: List2: {{ len $list2 }}| +{{ $i }}: Intersect: {{ intersect $.Pages .Pages | len }}| +{{ $i }}: Union: {{ union $.Pages .Pages | len }}| +{{ $i }}: SymDiff: {{ symdiff $.Pages .Pages | len }}| +{{ $i }}: Uniq: {{ append $.Pages .Pages | uniq | len }}| +{{ end }} + + +` + b := hugolib.Test(t, files) + + b.AssertFileContent("public/categories/cat-a/index.html", + "0: List1: 3|\n0: List2: 3|\n0: Intersect: 3|\n0: Union: 3|\n0: SymDiff: 0|\n0: Uniq: 3|\n\n\n1: List1: 3|", + "1: List2: 2|\n1: Intersect: 2|\n1: Union: 3|\n1: SymDiff: 1|\n1: Uniq: 3|\n\n\n2: List1: 3|\n2: List2: 1|", + "2: Intersect: 1|\n2: Union: 3|\n2: SymDiff: 2|\n2: Uniq: 3|", + ) +} diff --git a/tpl/collections/reflect_helpers.go b/tpl/collections/reflect_helpers.go index 56909d30e..4687acdde 100644 --- a/tpl/collections/reflect_helpers.go +++ b/tpl/collections/reflect_helpers.go @@ -18,6 +18,7 @@ import ( "fmt" "reflect" + "github.com/gohugoio/hugo/common/types" "github.com/mitchellh/hashstructure" ) @@ -60,7 +61,7 @@ func normalize(v reflect.Value) any { return f } } - return v.Interface() + return types.Unwrapv(v.Interface()) } // collects identities from the slices in seqs into a set. Numeric values are normalized,