mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
committed by
Bjørn Erik Pedersen
parent
7a43b928a6
commit
1a1b062a01
@@ -221,3 +221,24 @@ func (ns *Namespace) JoinPath(elements ...any) (string, error) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PathEscape returns the given string, applying percent-encoding to special
|
||||
// characters and reserved delimiters so it can be safely used as a segment
|
||||
// within a URL path.
|
||||
func (ns *Namespace) PathEscape(s any) (string, error) {
|
||||
ss, err := cast.ToStringE(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return url.PathEscape(ss), nil
|
||||
}
|
||||
|
||||
// PathUnescape returns the given string, replacing all percent-encoded
|
||||
// sequences with the corresponding unescaped characters.
|
||||
func (ns *Namespace) PathUnescape(s any) (string, error) {
|
||||
ss, err := cast.ToStringE(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return url.PathUnescape(ss)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ package urls
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/config/testconfig"
|
||||
@@ -105,3 +106,82 @@ func TestJoinPath(t *testing.T) {
|
||||
c.Assert(result, qt.Equals, test.expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathEscape(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
ns := newNs()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want string
|
||||
wantErr bool
|
||||
errCheck string
|
||||
}{
|
||||
{"string", "A/b/c?d=é&f=g+h", "A%2Fb%2Fc%3Fd=%C3%A9&f=g+h", false, ""},
|
||||
{"empty string", "", "", false, ""},
|
||||
{"integer", 6, "6", false, ""},
|
||||
{"float", 7.42, "7.42", false, ""},
|
||||
{"nil", nil, "", false, ""},
|
||||
{"slice", []int{}, "", true, "unable to cast"},
|
||||
{"map", map[string]string{}, "", true, "unable to cast"},
|
||||
{"struct", tstNoStringer{}, "", true, "unable to cast"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
c.Run(tt.name, func(c *qt.C) {
|
||||
got, err := ns.PathEscape(tt.input)
|
||||
if tt.wantErr {
|
||||
c.Assert(err, qt.IsNotNil, qt.Commentf("PathEscape(%v) should have failed", tt.input))
|
||||
if tt.errCheck != "" {
|
||||
c.Assert(err, qt.ErrorMatches, ".*"+regexp.QuoteMeta(tt.errCheck)+".*")
|
||||
}
|
||||
} else {
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(got, qt.Equals, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathUnescape(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
ns := newNs()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want string
|
||||
wantErr bool
|
||||
errCheck string
|
||||
}{
|
||||
{"string", "A%2Fb%2Fc%3Fd=%C3%A9&f=g+h", "A/b/c?d=é&f=g+h", false, ""},
|
||||
{"empty string", "", "", false, ""},
|
||||
{"integer", 6, "6", false, ""},
|
||||
{"float", 7.42, "7.42", false, ""},
|
||||
{"nil", nil, "", false, ""},
|
||||
{"slice", []int{}, "", true, "unable to cast"},
|
||||
{"map", map[string]string{}, "", true, "unable to cast"},
|
||||
{"struct", tstNoStringer{}, "", true, "unable to cast"},
|
||||
{"malformed hex", "bad%g0escape", "", true, "invalid URL escape"},
|
||||
{"incomplete hex", "trailing%", "", true, "invalid URL escape"},
|
||||
{"single hex digit", "trail%1", "", true, "invalid URL escape"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
c.Run(tt.name, func(c *qt.C) {
|
||||
got, err := ns.PathUnescape(tt.input)
|
||||
if tt.wantErr {
|
||||
c.Assert(err, qt.Not(qt.IsNil), qt.Commentf("PathUnescape(%v) should have failed", tt.input))
|
||||
if tt.errCheck != "" {
|
||||
c.Assert(err, qt.ErrorMatches, ".*"+regexp.QuoteMeta(tt.errCheck)+".*")
|
||||
}
|
||||
} else {
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(got, qt.Equals, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user