summaryrefslogtreecommitdiffstats
path: root/helpers
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-01-04 18:24:36 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-05-16 18:01:29 +0200
commit241b21b0fd34d91fccb2ce69874110dceae6f926 (patch)
treed4e0118eac7e9c42f065815447a70805f8d6ad3e /helpers
parent6aededf6b42011c3039f5f66487a89a8dd65e0e7 (diff)
Create a struct with all of Hugo's config options
Primary motivation is documentation, but it will also hopefully simplify the code. Also, * Lower case the default output format names; this is in line with the custom ones (map keys) and how it's treated all the places. This avoids doing `stringds.EqualFold` everywhere. Closes #10896 Closes #10620
Diffstat (limited to 'helpers')
-rw-r--r--helpers/content.go37
-rw-r--r--helpers/content_test.go71
-rw-r--r--helpers/general.go14
-rw-r--r--helpers/general_test.go79
-rw-r--r--helpers/path.go17
-rw-r--r--helpers/path_test.go85
-rw-r--r--helpers/pathspec.go11
-rw-r--r--helpers/pathspec_test.go62
-rw-r--r--helpers/testhelpers_test.go58
-rw-r--r--helpers/url.go33
-rw-r--r--helpers/url_test.go142
11 files changed, 220 insertions, 389 deletions
diff --git a/helpers/content.go b/helpers/content.go
index d04e34a07..510d496b9 100644
--- a/helpers/content.go
+++ b/helpers/content.go
@@ -50,30 +50,18 @@ type ContentSpec struct {
anchorNameSanitizer converter.AnchorNameSanitizer
getRenderer func(t hooks.RendererType, id any) any
- // SummaryLength is the length of the summary that Hugo extracts from a content.
- summaryLength int
-
- BuildFuture bool
- BuildExpired bool
- BuildDrafts bool
-
- Cfg config.Provider
+ Cfg config.AllProvider
}
// NewContentSpec returns a ContentSpec initialized
// with the appropriate fields from the given config.Provider.
-func NewContentSpec(cfg config.Provider, logger loggers.Logger, contentFs afero.Fs, ex *hexec.Exec) (*ContentSpec, error) {
+func NewContentSpec(cfg config.AllProvider, logger loggers.Logger, contentFs afero.Fs, ex *hexec.Exec) (*ContentSpec, error) {
spec := &ContentSpec{
- summaryLength: cfg.GetInt("summaryLength"),
- BuildFuture: cfg.GetBool("buildFuture"),
- BuildExpired: cfg.GetBool("buildExpired"),
- BuildDrafts: cfg.GetBool("buildDrafts"),
-
Cfg: cfg,
}
converterProvider, err := markup.NewConverterProvider(converter.ProviderConfig{
- Cfg: cfg,
+ Conf: cfg,
ContentFs: contentFs,
Logger: logger,
Exec: ex,
@@ -157,6 +145,9 @@ func (c *ContentSpec) SanitizeAnchorName(s string) string {
}
func (c *ContentSpec) ResolveMarkup(in string) string {
+ if c == nil {
+ panic("nil ContentSpec")
+ }
in = strings.ToLower(in)
switch in {
case "md", "markdown", "mdown":
@@ -194,17 +185,17 @@ func (c *ContentSpec) TruncateWordsByRune(in []string) (string, bool) {
count := 0
for index, word := range words {
- if count >= c.summaryLength {
+ if count >= c.Cfg.SummaryLength() {
return strings.Join(words[:index], " "), true
}
runeCount := utf8.RuneCountInString(word)
if len(word) == runeCount {
count++
- } else if count+runeCount < c.summaryLength {
+ } else if count+runeCount < c.Cfg.SummaryLength() {
count += runeCount
} else {
for ri := range word {
- if count >= c.summaryLength {
+ if count >= c.Cfg.SummaryLength() {
truncatedWords := append(words[:index], word[:ri])
return strings.Join(truncatedWords, " "), true
}
@@ -229,7 +220,7 @@ func (c *ContentSpec) TruncateWordsToWholeSentence(s string) (string, bool) {
wordCount++
lastWordIndex = i
- if wordCount >= c.summaryLength {
+ if wordCount >= c.Cfg.SummaryLength() {
break
}
@@ -283,19 +274,19 @@ func isEndOfSentence(r rune) bool {
func (c *ContentSpec) truncateWordsToWholeSentenceOld(content string) (string, bool) {
words := strings.Fields(content)
- if c.summaryLength >= len(words) {
+ if c.Cfg.SummaryLength() >= len(words) {
return strings.Join(words, " "), false
}
- for counter, word := range words[c.summaryLength:] {
+ for counter, word := range words[c.Cfg.SummaryLength():] {
if strings.HasSuffix(word, ".") ||
strings.HasSuffix(word, "?") ||
strings.HasSuffix(word, ".\"") ||
strings.HasSuffix(word, "!") {
- upper := c.summaryLength + counter + 1
+ upper := c.Cfg.SummaryLength() + counter + 1
return strings.Join(words[:upper], " "), (upper < len(words))
}
}
- return strings.Join(words[:c.summaryLength], " "), true
+ return strings.Join(words[:c.Cfg.SummaryLength()], " "), true
}
diff --git a/helpers/content_test.go b/helpers/content_test.go
index 54b7ef3f9..2909c0266 100644
--- a/helpers/content_test.go
+++ b/helpers/content_test.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Hugo Authors. All rights reserved.
+// Copyright 2023 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.
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package helpers
+package helpers_test
import (
"bytes"
@@ -19,12 +19,9 @@ import (
"strings"
"testing"
- "github.com/spf13/afero"
-
- "github.com/gohugoio/hugo/common/loggers"
- "github.com/gohugoio/hugo/config"
-
qt "github.com/frankban/quicktest"
+ "github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/helpers"
)
const tstHTMLContent = "<!DOCTYPE html><html><head><script src=\"http://two/foobar.js\"></script></head><body><nav><ul><li hugo-nav=\"section_0\"></li><li hugo-nav=\"section_1\"></li></ul></nav><article>content <a href=\"http://two/foobar\">foobar</a>. Follow up</article><p>This is some text.<br>And some more.</p></body></html>"
@@ -43,7 +40,7 @@ func TestTrimShortHTML(t *testing.T) {
{[]byte("<p>Hello</p>\n<ul>\n<li>list1</li>\n<li>list2</li>\n</ul>"), []byte("<p>Hello</p>\n<ul>\n<li>list1</li>\n<li>list2</li>\n</ul>")},
}
- c := newTestContentSpec()
+ c := newTestContentSpec(nil)
for i, test := range tests {
output := c.TrimShortHTML(test.input)
if !bytes.Equal(test.output, output) {
@@ -52,55 +49,23 @@ func TestTrimShortHTML(t *testing.T) {
}
}
-func TestStripEmptyNav(t *testing.T) {
- c := qt.New(t)
- cleaned := stripEmptyNav([]byte("do<nav>\n</nav>\n\nbedobedo"))
- c.Assert(cleaned, qt.DeepEquals, []byte("dobedobedo"))
-}
-
func TestBytesToHTML(t *testing.T) {
c := qt.New(t)
- c.Assert(BytesToHTML([]byte("dobedobedo")), qt.Equals, template.HTML("dobedobedo"))
-}
-
-func TestNewContentSpec(t *testing.T) {
- cfg := config.NewWithTestDefaults()
- c := qt.New(t)
-
- cfg.Set("summaryLength", 32)
- cfg.Set("buildFuture", true)
- cfg.Set("buildExpired", true)
- cfg.Set("buildDrafts", true)
-
- spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
-
- c.Assert(err, qt.IsNil)
- c.Assert(spec.summaryLength, qt.Equals, 32)
- c.Assert(spec.BuildFuture, qt.Equals, true)
- c.Assert(spec.BuildExpired, qt.Equals, true)
- c.Assert(spec.BuildDrafts, qt.Equals, true)
+ c.Assert(helpers.BytesToHTML([]byte("dobedobedo")), qt.Equals, template.HTML("dobedobedo"))
}
var benchmarkTruncateString = strings.Repeat("This is a sentence about nothing.", 20)
func BenchmarkTestTruncateWordsToWholeSentence(b *testing.B) {
- c := newTestContentSpec()
+ c := newTestContentSpec(nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.TruncateWordsToWholeSentence(benchmarkTruncateString)
}
}
-func BenchmarkTestTruncateWordsToWholeSentenceOld(b *testing.B) {
- c := newTestContentSpec()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- c.truncateWordsToWholeSentenceOld(benchmarkTruncateString)
- }
-}
-
func TestTruncateWordsToWholeSentence(t *testing.T) {
- c := newTestContentSpec()
+
type test struct {
input, expected string
max int
@@ -118,7 +83,9 @@ func TestTruncateWordsToWholeSentence(t *testing.T) {
{"This... is a more difficult test?", "This... is a more difficult test?", 1, false},
}
for i, d := range data {
- c.summaryLength = d.max
+ cfg := config.New()
+ cfg.Set("summaryLength", d.max)
+ c := newTestContentSpec(cfg)
output, truncated := c.TruncateWordsToWholeSentence(d.input)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
@@ -131,7 +98,7 @@ func TestTruncateWordsToWholeSentence(t *testing.T) {
}
func TestTruncateWordsByRune(t *testing.T) {
- c := newTestContentSpec()
+
type test struct {
input, expected string
max int
@@ -153,7 +120,9 @@ func TestTruncateWordsByRune(t *testing.T) {
{" \nThis is not a sentence\n ", "This is not", 3, true},
}
for i, d := range data {
- c.summaryLength = d.max
+ cfg := config.New()
+ cfg.Set("summaryLength", d.max)
+ c := newTestContentSpec(cfg)
output, truncated := c.TruncateWordsByRune(strings.Fields(d.input))
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
@@ -168,7 +137,7 @@ func TestTruncateWordsByRune(t *testing.T) {
func TestExtractTOCNormalContent(t *testing.T) {
content := []byte("<nav>\n<ul>\nTOC<li><a href=\"#")
- actualTocLessContent, actualToc := ExtractTOC(content)
+ actualTocLessContent, actualToc := helpers.ExtractTOC(content)
expectedTocLess := []byte("TOC<li><a href=\"#")
expectedToc := []byte("<nav id=\"TableOfContents\">\n<ul>\n")
@@ -184,7 +153,7 @@ func TestExtractTOCNormalContent(t *testing.T) {
func TestExtractTOCGreaterThanSeventy(t *testing.T) {
content := []byte("<nav>\n<ul>\nTOC This is a very long content which will definitely be greater than seventy, I promise you that.<li><a href=\"#")
- actualTocLessContent, actualToc := ExtractTOC(content)
+ actualTocLessContent, actualToc := helpers.ExtractTOC(content)
// Because the start of Toc is greater than 70+startpoint of <li> content and empty TOC will be returned
expectedToc := []byte("")
@@ -200,7 +169,7 @@ func TestExtractTOCGreaterThanSeventy(t *testing.T) {
func TestExtractNoTOC(t *testing.T) {
content := []byte("TOC")
- actualTocLessContent, actualToc := ExtractTOC(content)
+ actualTocLessContent, actualToc := helpers.ExtractTOC(content)
expectedToc := []byte("")
if !bytes.Equal(actualTocLessContent, content) {
@@ -225,7 +194,7 @@ func TestTotalWords(t *testing.T) {
{"One, Two, Three", 3},
{totalWordsBenchmarkString, 400},
} {
- actualWordCount := TotalWords(this.s)
+ actualWordCount := helpers.TotalWords(this.s)
if actualWordCount != this.words {
t.Errorf("[%d] Actual word count (%d) for test string (%s) did not match %d", i, actualWordCount, this.s, this.words)
@@ -236,7 +205,7 @@ func TestTotalWords(t *testing.T) {
func BenchmarkTotalWords(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
- wordCount := TotalWords(totalWordsBenchmarkString)
+ wordCount := helpers.TotalWords(totalWordsBenchmarkString)
if wordCount != 400 {
b.Fatal("Wordcount error")
}
diff --git a/helpers/general.go b/helpers/general.go
index 920376227..e8d8bdecc 100644
--- a/helpers/general.go
+++ b/helpers/general.go
@@ -43,20 +43,6 @@ import (
// FilePathSeparator as defined by os.Separator.
const FilePathSeparator = string(filepath.Separator)
-// FindAvailablePort returns an available and valid TCP port.
-func FindAvailablePort() (*net.TCPAddr, error) {
- l, err := net.Listen("tcp", ":0")
- if err == nil {
- defer l.Close()
- addr := l.Addr()
- if a, ok := addr.(*net.TCPAddr); ok {
- return a, nil
- }
- return nil, fmt.Errorf("unable to obtain a valid tcp port: %v", addr)
- }
- return nil, err
-}
-
// TCPListen starts listening on a valid TCP port.
func TCPListen() (net.Listener, *net.TCPAddr, error) {
l, err := net.Listen("tcp", ":0")
diff --git a/helpers/general_test.go b/helpers/general_test.go
index b2ee03f15..9b2e4fc58 100644
--- a/helpers/general_test.go
+++ b/helpers/general_test.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Hugo Authors. All rights reserved.
+// Copyright 2023 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.
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package helpers
+package helpers_test
import (
"fmt"
@@ -21,17 +21,14 @@ import (
"time"
"github.com/gohugoio/hugo/common/loggers"
- "github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/helpers"
qt "github.com/frankban/quicktest"
"github.com/spf13/afero"
)
func TestResolveMarkup(t *testing.T) {
- c := qt.New(t)
- cfg := config.NewWithTestDefaults()
- spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
- c.Assert(err, qt.IsNil)
+ spec := newTestContentSpec(nil)
for i, this := range []struct {
in string
@@ -61,7 +58,7 @@ func TestResolveMarkup(t *testing.T) {
func TestDistinctLoggerDoesNotLockOnWarningPanic(t *testing.T) {
// Testing to make sure logger mutex doesn't lock if warnings cause panics.
// func Warnf() of DistinctLogger is defined in general.go
- l := NewDistinctLogger(loggers.NewWarningLogger())
+ l := helpers.NewDistinctLogger(loggers.NewWarningLogger())
// Set PanicOnWarning to true to reproduce issue 9380
// Ensure global variable loggers.PanicOnWarning is reset to old value after test
@@ -123,7 +120,7 @@ func TestFirstUpper(t *testing.T) {
{"", ""},
{"å", "Å"},
} {
- result := FirstUpper(this.in)
+ result := helpers.FirstUpper(this.in)
if result != this.expect {
t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
}
@@ -143,7 +140,7 @@ func TestHasStringsPrefix(t *testing.T) {
{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, true},
{[]string{"abra", "ca"}, []string{"abra", "ca", "dabra"}, false},
} {
- result := HasStringsPrefix(this.s, this.prefix)
+ result := helpers.HasStringsPrefix(this.s, this.prefix)
if result != this.expect {
t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
}
@@ -162,7 +159,7 @@ func TestHasStringsSuffix(t *testing.T) {
{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, false},
{[]string{"abra", "ca", "dabra"}, []string{"ca", "dabra"}, true},
} {
- result := HasStringsSuffix(this.s, this.suffix)
+ result := helpers.HasStringsSuffix(this.s, this.suffix)
if result != this.expect {
t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
}
@@ -239,7 +236,7 @@ func TestSliceToLower(t *testing.T) {
}
for _, test := range tests {
- res := SliceToLower(test.value)
+ res := helpers.SliceToLower(test.value)
for i, val := range res {
if val != test.expected[i] {
t.Errorf("Case mismatch. Expected %s, got %s", test.expected[i], res[i])
@@ -251,34 +248,34 @@ func TestSliceToLower(t *testing.T) {
func TestReaderContains(t *testing.T) {
c := qt.New(t)
for i, this := range append(containsBenchTestData, containsAdditionalTestData...) {
- result := ReaderContains(strings.NewReader(this.v1), this.v2)
+ result := helpers.ReaderContains(strings.NewReader(this.v1), this.v2)
if result != this.expect {
t.Errorf("[%d] got %t but expected %t", i, result, this.expect)
}
}
- c.Assert(ReaderContains(nil, []byte("a")), qt.Equals, false)
- c.Assert(ReaderContains(nil, nil), qt.Equals, false)
+ c.Assert(helpers.ReaderContains(nil, []byte("a")), qt.Equals, false)
+ c.Assert(helpers.ReaderContains(nil, nil), qt.Equals, false)
}
func TestGetTitleFunc(t *testing.T) {
title := "somewhere over the rainbow"
c := qt.New(t)
- c.Assert(GetTitleFunc("go")(title), qt.Equals, "Somewhere Over The Rainbow")
- c.Assert(GetTitleFunc("chicago")(title), qt.Equals, "Somewhere over the Rainbow")
- c.Assert(GetTitleFunc("Chicago")(title), qt.Equals, "Somewhere over the Rainbow")
- c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
- c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
- c.Assert(GetTitleFunc("")(title), qt.Equals, "Somewhere Over the Rainbow")
- c.Assert(GetTitleFunc("unknown")(title), qt.Equals, "Somewhere Over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("go")(title), qt.Equals, "Somewhere Over The Rainbow")
+ c.Assert(helpers.GetTitleFunc("chicago")(title), qt.Equals, "Somewhere over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("Chicago")(title), qt.Equals, "Somewhere over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("")(title), qt.Equals, "Somewhere Over the Rainbow")
+ c.Assert(helpers.GetTitleFunc("unknown")(title), qt.Equals, "Somewhere Over the Rainbow")
}
func BenchmarkReaderContains(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i, this := range containsBenchTestData {
- result := ReaderContains(strings.NewReader(this.v1), this.v2)
+ result := helpers.ReaderContains(strings.NewReader(this.v1), this.v2)
if result != this.expect {
b.Errorf("[%d] got %t but expected %t", i, result, this.expect)
}
@@ -288,7 +285,7 @@ func BenchmarkReaderContains(b *testing.B) {
func TestUniqueStrings(t *testing.T) {
in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
- output := UniqueStrings(in)
+ output := helpers.UniqueStrings(in)
expected := []string{"a", "b", "c", "", "d"}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Expected %#v, got %#v\n", expected, output)
@@ -297,7 +294,7 @@ func TestUniqueStrings(t *testing.T) {
func TestUniqueStringsReuse(t *testing.T) {
in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
- output := UniqueStringsReuse(in)
+ output := helpers.UniqueStringsReuse(in)
expected := []string{"a", "b", "c", "", "d"}
if !reflect.DeepEqual(output, expected) {
t.Errorf("Expected %#v, got %#v\n", expected, output)
@@ -307,18 +304,10 @@ func TestUniqueStringsReuse(t *testing.T) {
func TestUniqueStringsSorted(t *testing.T) {
c := qt.New(t)
in := []string{"a", "a", "b", "c", "b", "", "a", "", "d"}
- output := UniqueStringsSorted(in)
+ output := helpers.UniqueStringsSorted(in)
expected := []string{"", "a", "b", "c", "d"}
c.Assert(output, qt.DeepEquals, expected)
- c.Assert(UniqueStringsSorted(nil), qt.IsNil)
-}
-
-func TestFindAvailablePort(t *testing.T) {
- c := qt.New(t)
- addr, err := FindAvailablePort()
- c.Assert(err, qt.IsNil)
- c.Assert(addr, qt.Not(qt.IsNil))
- c.Assert(addr.Port > 0, qt.Equals, true)
+ c.Assert(helpers.UniqueStringsSorted(nil), qt.IsNil)
}
func TestFastMD5FromFile(t *testing.T) {
@@ -357,23 +346,23 @@ func TestFastMD5FromFile(t *testing.T) {
defer bf1.Close()
defer bf2.Close()
- m1, err := MD5FromFileFast(sf1)
+ m1, err := helpers.MD5FromFileFast(sf1)
c.Assert(err, qt.IsNil)
c.Assert(m1, qt.Equals, "e9c8989b64b71a88b4efb66ad05eea96")
- m2, err := MD5FromFileFast(sf2)
+ m2, err := helpers.MD5FromFileFast(sf2)
c.Assert(err, qt.IsNil)
c.Assert(m2, qt.Not(qt.Equals), m1)
- m3, err := MD5FromFileFast(bf1)
+ m3, err := helpers.MD5FromFileFast(bf1)
c.Assert(err, qt.IsNil)
c.Assert(m3, qt.Not(qt.Equals), m2)
- m4, err := MD5FromFileFast(bf2)
+ m4, err := helpers.MD5FromFileFast(bf2)
c.Assert(err, qt.IsNil)
c.Assert(m4, qt.Not(qt.Equals), m3)
- m5, err := MD5FromReader(bf2)
+ m5, err := helpers.MD5FromReader(bf2)
c.Assert(err, qt.IsNil)
c.Assert(m5, qt.Not(qt.Equals), m4)
}
@@ -394,11 +383,11 @@ func BenchmarkMD5FromFileFast(b *testing.B) {
}
b.StartTimer()
if full {
- if _, err := MD5FromReader(f); err != nil {
+ if _, err := helpers.MD5FromReader(f); err != nil {
b.Fatal(err)
}
} else {
- if _, err := MD5FromFileFast(f); err != nil {
+ if _, err := helpers.MD5FromFileFast(f); err != nil {
b.Fatal(err)
}
}
@@ -413,7 +402,7 @@ func BenchmarkUniqueStrings(b *testing.B) {
b.Run("Safe", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- result := UniqueStrings(input)
+ result := helpers.UniqueStrings(input)
if len(result) != 6 {
b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
}
@@ -432,7 +421,7 @@ func BenchmarkUniqueStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
inputc := inputs[i]
- result := UniqueStringsReuse(inputc)
+ result := helpers.UniqueStringsReuse(inputc)
if len(result) != 6 {
b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
}
@@ -451,7 +440,7 @@ func BenchmarkUniqueStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
inputc := inputs[i]
- result := UniqueStringsSorted(inputc)
+ result := helpers.UniqueStringsSorted(inputc)
if len(result) != 6 {
b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
}
diff --git a/helpers/path.go b/helpers/path.go
index 7bc216ec8..00c541bab 100644
--- a/helpers/path.go
+++ b/helpers/path.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Hugo Authors. All rights reserved.
+// Copyright 2023 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.
@@ -28,8 +28,6 @@ import (
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/text"
- "github.com/gohugoio/hugo/config"
-
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/hugio"
@@ -54,7 +52,7 @@ func (p *PathSpec) MakePathsSanitized(paths []string) {
// MakePathSanitized creates a Unicode-sanitized string, with the spaces replaced
func (p *PathSpec) MakePathSanitized(s string) string {
- if p.DisablePathToLower {
+ if p.Cfg.DisablePathToLower() {
return p.MakePath(s)
}
return strings.ToLower(p.MakePath(s))
@@ -91,7 +89,7 @@ func ishex(c rune) bool {
// Hyphens in the original input are maintained.
// Spaces will be replaced with a single hyphen, and sequential replacement hyphens will be reduced to one.
func (p *PathSpec) UnicodeSanitize(s string) string {
- if p.RemovePathAccents {
+ if p.Cfg.RemovePathAccents() {
s = text.RemoveAccentsString(s)
}
@@ -128,7 +126,7 @@ func (p *PathSpec) UnicodeSanitize(s string) string {
return string(target)
}
-func makePathRelative(inPath string, possibleDirectories ...string) (string, error) {
+func MakePathRelative(inPath string, possibleDirectories ...string) (string, error) {
for _, currentPath := range possibleDirectories {
if strings.HasPrefix(inPath, currentPath) {
return strings.TrimPrefix(inPath, currentPath), nil
@@ -394,8 +392,8 @@ func OpenFileForWriting(fs afero.Fs, filename string) (afero.File, error) {
// GetCacheDir returns a cache dir from the given filesystem and config.
// The dir will be created if it does not exist.
-func GetCacheDir(fs afero.Fs, cfg config.Provider) (string, error) {
- cacheDir := getCacheDir(cfg)
+func GetCacheDir(fs afero.Fs, cacheDir string) (string, error) {
+ cacheDir = cacheDirDefault(cacheDir)
if cacheDir != "" {
exists, err := DirExists(cacheDir, fs)
if err != nil {
@@ -414,9 +412,8 @@ func GetCacheDir(fs afero.Fs, cfg config.Provider) (string, error) {
return GetTempDir("hugo_cache", fs), nil
}
-func getCacheDir(cfg config.Provider) string {
+func cacheDirDefault(cacheDir string) string {
// Always use the cacheDir config if set.
- cacheDir := cfg.GetString("cacheDir")
if len(cacheDir) > 1 {
return addTrailingFileSeparator(cacheDir)
}
diff --git a/helpers/path_test.go b/helpers/path_test.go
index 1f206a881..85081c5be 100644
--- a/helpers/path_test.go
+++ b/helpers/path_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2023 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.
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package helpers
+package helpers_test
import (
"fmt"
@@ -24,16 +24,12 @@ import (
"testing"
"time"
- "github.com/gohugoio/hugo/langs"
-
qt "github.com/frankban/quicktest"
-
- "github.com/gohugoio/hugo/hugofs"
+ "github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
)
func TestMakePath(t *testing.T) {
- c := qt.New(t)
tests := []struct {
input string
expected string
@@ -60,13 +56,7 @@ func TestMakePath(t *testing.T) {
}
for _, test := range tests {
- v := newTestCfg()
- v.Set("removePathAccents", test.removeAccents)
-
- l := langs.NewDefaultLanguage(v)
- p, err := NewPathSpec(hugofs.NewMem(v), l, nil)
- c.Assert(err, qt.IsNil)
-
+ p := newTestPathSpec("removePathAccents", test.removeAccents)
output := p.MakePath(test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
@@ -75,9 +65,7 @@ func TestMakePath(t *testing.T) {
}
func TestMakePathSanitized(t *testing.T) {
- v := newTestCfg()
-
- p, _ := NewPathSpec(hugofs.NewMem(v), v, nil)
+ p := newTestPathSpec()
tests := []struct {
input string
@@ -100,12 +88,7 @@ func TestMakePathSanitized(t *testing.T) {
}
func TestMakePathSanitizedDisablePathToLower(t *testing.T) {
- v := newTestCfg()
-
- v.Set("disablePathToLower", true)
-
- l := langs.NewDefaultLanguage(v)
- p, _ := NewPathSpec(hugofs.NewMem(v), l, nil)
+ p := newTestPathSpec("disablePathToLower", true)
tests := []struct {
input string
@@ -138,12 +121,12 @@ func TestMakePathRelative(t *testing.T) {
}
for i, d := range data {
- output, _ := makePathRelative(d.inPath, d.path1, d.path2)
+ output, _ := helpers.MakePathRelative(d.inPath, d.path1, d.path2)
if d.output != output {
t.Errorf("Test #%d failed. Expected %q got %q", i, d.output, output)
}
}
- _, error := makePathRelative("a/b/c.ss", "/a/c", "/d/c", "/e/f")
+ _, error := helpers.MakePathRelative("a/b/c.ss", "/a/c", "/d/c", "/e/f")
if error == nil {
t.Errorf("Test failed, expected error")
@@ -181,7 +164,7 @@ func doTestGetDottedRelativePath(urlFixer func(string) string, t *testing.T) {
{"/404.html", "./"},
}
for i, d := range data {
- output := GetDottedRelativePath(d.input)
+ output := helpers.GetDottedRelativePath(d.input)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
@@ -198,7 +181,7 @@ func TestMakeTitle(t *testing.T) {
{"make_title", "make_title"},
}
for i, d := range data {
- output := MakeTitle(d.input)
+ output := helpers.MakeTitle(d.input)
if d.expected != output {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
}
@@ -219,7 +202,7 @@ func TestDirExists(t *testing.T) {
{"./..", true},
{"./../", true},
{os.TempDir(), true},
- {os.TempDir() + FilePathSeparator, true},
+ {os.TempDir() + helpers.FilePathSeparator, true},
{"/", true},
{"/some-really-random-directory-name", false},
{"/some/really/random/directory/name", false},
@@ -228,7 +211,7 @@ func TestDirExists(t *testing.T) {
}
for i, d := range data {
- exists, _ := DirExists(filepath.FromSlash(d.input), new(afero.OsFs))
+ exists, _ := helpers.DirExists(filepath.FromSlash(d.input), new(afero.OsFs))
if d.expected != exists {
t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
}
@@ -249,7 +232,7 @@ func TestIsDir(t *testing.T) {
for i, d := range data {
- exists, _ := IsDir(d.input, new(afero.OsFs))
+ exists, _ := helpers.IsDir(d.input, new(afero.OsFs))
if d.expected != exists {
t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
}
@@ -310,7 +293,7 @@ func TestExists(t *testing.T) {
{nonExistentDir, false, nil},
}
for i, d := range data {
- exists, err := Exists(d.input, new(afero.OsFs))
+ exists, err := helpers.Exists(d.input, new(afero.OsFs))
if d.expectedResult != exists {
t.Errorf("Test %d failed. Expected result %t got %t", i, d.expectedResult, exists)
}
@@ -341,7 +324,7 @@ func TestAbsPathify(t *testing.T) {
for i, d := range data {
// todo see comment in AbsPathify
- ps := newTestDefaultPathSpec("workingDir", d.workingDir)
+ ps := newTestPathSpec("workingDir", d.workingDir)
expected := ps.AbsPathify(d.inPath)
if d.expected != expected {
@@ -351,7 +334,7 @@ func TestAbsPathify(t *testing.T) {
t.Logf("Running platform specific path tests for %s", runtime.GOOS)
if runtime.GOOS == "windows" {
for i, d := range windowsData {
- ps := newTestDefaultPathSpec("workingDir", d.workingDir)
+ ps := newTestPathSpec("workingDir", d.workingDir)
expected := ps.AbsPathify(d.inPath)
if d.expected != expected {
@@ -360,7 +343,7 @@ func TestAbsPathify(t *testing.T)