diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-01-02 12:33:26 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-03-23 18:51:22 +0100 |
commit | 597e418cb02883418f2cebb41400e8e61413f651 (patch) | |
tree | 177ad9c540b2583b6dab138c9f0490d28989c7f7 /resources/page/pages_sort_test.go | |
parent | 44f5c1c14cb1f42cc5f01739c289e9cfc83602af (diff) |
Make Page an interface
The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct.
This is all a preparation step for issue #5074, "pages from other data sources".
But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes.
Most notable changes:
* The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday.
This means that any markdown will partake in the global ToC and footnote context etc.
* The Custom Output formats are now "fully virtualized". This removes many of the current limitations.
* The taxonomy list type now has a reference to the `Page` object.
This improves the taxonomy template `.Title` situation and make common template constructs much simpler.
See #5074
Fixes #5763
Fixes #5758
Fixes #5090
Fixes #5204
Fixes #4695
Fixes #5607
Fixes #5707
Fixes #5719
Fixes #3113
Fixes #5706
Fixes #5767
Fixes #5723
Fixes #5769
Fixes #5770
Fixes #5771
Fixes #5759
Fixes #5776
Fixes #5777
Fixes #5778
Diffstat (limited to 'resources/page/pages_sort_test.go')
-rw-r--r-- | resources/page/pages_sort_test.go | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/resources/page/pages_sort_test.go b/resources/page/pages_sort_test.go new file mode 100644 index 000000000..c781de2f3 --- /dev/null +++ b/resources/page/pages_sort_test.go @@ -0,0 +1,279 @@ +// Copyright 2019 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package page + +import ( + "fmt" + "testing" + "time" + + "github.com/gohugoio/hugo/resources/resource" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDefaultSort(t *testing.T) { + t.Parallel() + d1 := time.Now() + d2 := d1.Add(-1 * time.Hour) + d3 := d1.Add(-2 * time.Hour) + d4 := d1.Add(-3 * time.Hour) + + p := createSortTestPages(4) + + // first by weight + setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "a", "c", "d"}, [4]int{4, 3, 2, 1}, p) + SortByDefault(p) + + assert.Equal(t, 1, p[0].Weight()) + + // Consider zero weight, issue #2673 + setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "a", "d", "c"}, [4]int{0, 0, 0, 1}, p) + SortByDefault(p) + + assert.Equal(t, 1, p[0].Weight()) + + // next by date + setSortVals([4]time.Time{d3, d4, d1, d2}, [4]string{"a", "b", "c", "d"}, [4]int{1, 1, 1, 1}, p) + SortByDefault(p) + assert.Equal(t, d1, p[0].Date()) + + // finally by link title + setSortVals([4]time.Time{d3, d3, d3, d3}, [4]string{"b", "c", "a", "d"}, [4]int{1, 1, 1, 1}, p) + SortByDefault(p) + assert.Equal(t, "al", p[0].LinkTitle()) + assert.Equal(t, "bl", p[1].LinkTitle()) + assert.Equal(t, "cl", p[2].LinkTitle()) +} + +// https://github.com/gohugoio/hugo/issues/4953 +func TestSortByLinkTitle(t *testing.T) { + t.Parallel() + assert := require.New(t) + pages := createSortTestPages(6) + + for i, p := range pages { + pp := p.(*testPage) + if i < 5 { + pp.title = fmt.Sprintf("title%d", i) + } + + if i > 2 { + pp.linkTitle = fmt.Sprintf("linkTitle%d", i) + } + + } + + pages.shuffle() + + bylt := pages.ByLinkTitle() + + for i, p := range bylt { + msg := fmt.Sprintf("test: %d", i) + if i < 3 { + assert.Equal(fmt.Sprintf("linkTitle%d", i+3), p.LinkTitle(), msg) + } else { + assert.Equal(fmt.Sprintf("title%d", i-3), p.LinkTitle(), msg) + } + } +} + +func TestSortByN(t *testing.T) { + t.Parallel() + d1 := time.Now() + d2 := d1.Add(-2 * time.Hour) + d3 := d1.Add(-10 * time.Hour) + d4 := d1.Add(-20 * time.Hour) + + p := createSortTestPages(4) + + for i, this := range []struct { + sortFunc func(p Pages) Pages + assertFunc func(p Pages) bool + }{ + {(Pages).ByWeight, func(p Pages) bool { return p[0].Weight() == 1 }}, + {(Pages).ByTitle, func(p Pages) bool { return p[0].Title() == "ab" }}, + {(Pages).ByLinkTitle, func(p Pages) bool { return p[0].LinkTitle() == "abl" }}, + {(Pages).ByDate, func(p Pages) bool { return p[0].Date() == d4 }}, + {(Pages).ByPublishDate, func(p Pages) bool { return p[0].PublishDate() == d4 }}, + {(Pages).ByExpiryDate, func(p Pages) bool { return p[0].ExpiryDate() == d4 }}, + {(Pages).ByLastmod, func(p Pages) bool { return p[1].Lastmod() == d3 }}, + {(Pages).ByLength, func(p Pages) bool { return p[0].(resource.LengthProvider).Len() == len(p[0].(*testPage).content) }}, + } { + setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "ab", "cde", "fg"}, [4]int{0, 3, 2, 1}, p) + + sorted := this.sortFunc(p) + if !this.assertFunc(sorted) { + t.Errorf("[%d] sort error", i) + } + } + +} + +func TestLimit(t *testing.T) { + t.Parallel() + p := createSortTestPages(10) + firstFive := p.Limit(5) + assert.Equal(t, 5, len(firstFive)) + for i := 0; i < 5; i++ { + assert.Equal(t, p[i], firstFive[i]) + } + assert.Equal(t, p, p.Limit(10)) + assert.Equal(t, p, p.Limit(11)) +} + +func TestPageSortReverse(t *testing.T) { + t.Parallel() + p1 := createSortTestPages(10) + assert.Equal(t, 0, p1[0].(*testPage).fuzzyWordCount) + assert.Equal(t, 9, p1[9].(*testPage).fuzzyWordCount) + p2 := p1.Reverse() + assert.Equal(t, 9, p2[0].(*testPage).fuzzyWordCount) + assert.Equal(t, 0, p2[9].(*testPage).fuzzyWordCount) + // cached + assert.True(t, pagesEqual(p2, p1.Reverse())) +} + +func TestPageSortByParam(t *testing.T) { + t.Parallel() + var k interface{} = "arbitrarily.nested" + + unsorted := createSortTestPages(10) + delete(unsorted[9].Params(), "arbitrarily") + + firstSetValue, _ := unsorted[0].Param(k) + secondSetValue, _ := unsorted[1].Param(k) + lastSetValue, _ := unsorted[8].Param(k) + unsetValue, _ := unsorted[9].Param(k) + + assert.Equal(t, "xyz100", firstSetValue) + assert.Equal(t, "xyz99", secondSetValue) + assert.Equal(t, "xyz92", lastSetValue) + assert.Equal(t, nil, unsetValue) + + sorted := unsorted.ByParam("arbitrarily.nested") + firstSetSortedValue, _ := sorted[0].Param(k) + secondSetSortedValue, _ := sorted[1].Param(k) + lastSetSortedValue, _ := sorted[8].Param(k) + unsetSortedValue, _ := sorted[9].Param(k) + + assert.Equal(t, firstSetValue, firstSetSortedValue) + assert.Equal(t, secondSetValue, lastSetSortedValue) + assert.Equal(t, lastSetValue, secondSetSortedValue) + assert.Equal(t, unsetValue, unsetSortedValue) +} + +func TestPageSortByParamNumeric(t *testing.T) { + t.Parallel() + var k interface{} = "arbitrarily.nested" + + n := 10 + unsorted := createSortTestPages(n) + for i := 0; i < n; i++ { + v := 100 - i + if i%2 == 0 { + v = 100.0 - i + } + + unsorted[i].(*testPage).params = map[string]interface{}{ + "arbitrarily": map[string]interface{}{ + "nested": v, + }, + } + } + delete(unsorted[9].Params(), "arbitrarily") + + firstSetValue, _ := unsorted[0].Param(k) + secondSetValue, _ := unsorted[1].Param(k) + lastSetValue, _ := unsorted[8].Param(k) + unsetValue, _ := unsorted[9].Param(k) + + assert.Equal(t, 100, firstSetValue) + assert.Equal(t, 99, secondSetValue) + assert.Equal(t, 92, lastSetValue) + assert.Equal(t, nil, unsetValue) + + sorted := unsorted.ByParam("arbitrarily.nested") + firstSetSortedValue, _ := sorted[0].Param(k) + secondSetSortedValue, _ := sorted[1].Param(k) + lastSetSortedValue, _ := sorted[8].Param(k) + unsetSortedValue, _ := sorted[9].Param(k) + + assert.Equal(t, 92, firstSetSortedValue) + assert.Equal(t, 93, secondSetSortedValue) + assert.Equal(t, 100, lastSetSortedValue) + assert.Equal(t, unsetValue, unsetSortedValue) +} + +func BenchmarkSortByWeightAndReverse(b *testing.B) { + p := createSortTestPages(300) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + p = p.ByWeight().Reverse() + } +} + +func setSortVals(dates [4]time.Time, titles [4]string, weights [4]int, pages Pages) { + for i := range dates { + this := pages[i].(*testPage) + other := pages[len(dates)-1-i].(*testPage) + + this.date = dates[i] + this.lastMod = dates[i] + this.weight = weights[i] + this.title = titles[i] + // make sure we compare apples and ... apples ... + other.linkTitle = this.Title() + "l" + other.pubDate = dates[i] + other.expiryDate = dates[i] + other.content = titles[i] + "_content" + } + lastLastMod := pages[2].Lastmod() + pages[2].(*testPage).lastMod = pages[1].Lastmod() + pages[1].(*testPage).lastMod = lastLastMod + + for _, p := range pages { + p.(*testPage).content = "" + } + +} + +func createSortTestPages(num int) Pages { + pages := make(Pages, num) + + for i := 0; i < num; i++ { + p := newTestPage() + p.path = fmt.Sprintf("/x/y/p%d.md", i) + p.params = map[string]interface{}{ + "arbitrarily": map[string]interface{}{ + "nested": ("xyz" + fmt.Sprintf("%v", 100-i)), + }, + } + + w := 5 + + if i%2 == 0 { + w = 10 + } + p.fuzzyWordCount = i + p.weight = w + p.description = "initial" + + pages[i] = p + } + + return pages +} |