mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
241b21b0fd
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
349 lines
8.5 KiB
Go
349 lines
8.5 KiB
Go
// Copyright 2017 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 data
|
|
|
|
import (
|
|
"bytes"
|
|
"html/template"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gohugoio/hugo/common/maps"
|
|
|
|
qt "github.com/frankban/quicktest"
|
|
)
|
|
|
|
func TestGetCSV(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
for i, test := range []struct {
|
|
sep string
|
|
url string
|
|
content string
|
|
expect any
|
|
}{
|
|
// Remotes
|
|
{
|
|
",",
|
|
`http://success/`,
|
|
"gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm\n",
|
|
[][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
|
|
},
|
|
{
|
|
",",
|
|
`http://error.extra.field/`,
|
|
"gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm,EXTRA\n",
|
|
false,
|
|
},
|
|
{
|
|
",",
|
|
`http://nofound/404`,
|
|
``,
|
|
false,
|
|
},
|
|
|
|
// Locals
|
|
{
|
|
";",
|
|
"pass/semi",
|
|
"gomeetup;city\nyes;Sydney\nyes;San Francisco\nyes;Stockholm\n",
|
|
[][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
|
|
},
|
|
{
|
|
";",
|
|
"fail/no-file",
|
|
"",
|
|
false,
|
|
},
|
|
} {
|
|
|
|
c.Run(test.url, func(c *qt.C) {
|
|
msg := qt.Commentf("Test %d", i)
|
|
|
|
ns := newTestNs()
|
|
|
|
// Setup HTTP test server
|
|
var srv *httptest.Server
|
|
srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
|
|
if !hasHeaderValue(r.Header, "Accept", "text/csv") && !hasHeaderValue(r.Header, "Accept", "text/plain") {
|
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if r.URL.Path == "/404" {
|
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
w.Header().Add("Content-type", "text/csv")
|
|
|
|
w.Write([]byte(test.content))
|
|
})
|
|
defer func() { srv.Close() }()
|
|
|
|
// Setup local test file for schema-less URLs
|
|
if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
|
|
f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url))
|
|
c.Assert(err, qt.IsNil, msg)
|
|
f.WriteString(test.content)
|
|
f.Close()
|
|
}
|
|
|
|
// Get on with it
|
|
got, err := ns.GetCSV(test.sep, test.url)
|
|
|
|
if _, ok := test.expect.(bool); ok {
|
|
c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 1)
|
|
c.Assert(got, qt.IsNil)
|
|
return
|
|
}
|
|
|
|
c.Assert(err, qt.IsNil, msg)
|
|
c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0)
|
|
c.Assert(got, qt.Not(qt.IsNil), msg)
|
|
c.Assert(got, qt.DeepEquals, test.expect, msg)
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
func TestGetJSON(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
for i, test := range []struct {
|
|
url string
|
|
content string
|
|
expect any
|
|
}{
|
|
{
|
|
`http://success/`,
|
|
`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
|
|
map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
|
|
},
|
|
{
|
|
`http://malformed/`,
|
|
`{gomeetup:["Sydney","San Francisco","Stockholm"]}`,
|
|
false,
|
|
},
|
|
{
|
|
`http://nofound/404`,
|
|
``,
|
|
false,
|
|
},
|
|
// Locals
|
|
{
|
|
"pass/semi",
|
|
`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
|
|
map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
|
|
},
|
|
{
|
|
"fail/no-file",
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
`pass/üńīçøðê-url.json`,
|
|
`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
|
|
map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
|
|
},
|
|
} {
|
|
|
|
c.Run(test.url, func(c *qt.C) {
|
|
|
|
msg := qt.Commentf("Test %d", i)
|
|
ns := newTestNs()
|
|
|
|
// Setup HTTP test server
|
|
var srv *httptest.Server
|
|
srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
|
|
if !hasHeaderValue(r.Header, "Accept", "application/json") {
|
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if r.URL.Path == "/404" {
|
|
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
w.Header().Add("Content-type", "application/json")
|
|
|
|
w.Write([]byte(test.content))
|
|
})
|
|
defer func() { srv.Close() }()
|
|
|
|
// Setup local test file for schema-less URLs
|
|
if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
|
|
f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url))
|
|
c.Assert(err, qt.IsNil, msg)
|
|
f.WriteString(test.content)
|
|
f.Close()
|
|
}
|
|
|
|
// Get on with it
|
|
got, _ := ns.GetJSON(test.url)
|
|
|
|
if _, ok := test.expect.(bool); ok {
|
|
c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 1)
|
|
return
|
|
}
|
|
|
|
c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0, msg)
|
|
c.Assert(got, qt.Not(qt.IsNil), msg)
|
|
c.Assert(got, qt.DeepEquals, test.expect)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHeaders(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
for _, test := range []struct {
|
|
name string
|
|
headers any
|
|
assert func(c *qt.C, headers string)
|
|
}{
|
|
{
|
|
`Misc header variants`,
|
|
map[string]any{
|
|
"Accept-Charset": "utf-8",
|
|
"Max-forwards": "10",
|
|
"X-Int": 32,
|
|
"X-Templ": template.HTML("a"),
|
|
"X-Multiple": []string{"a", "b"},
|
|
"X-MultipleInt": []int{3, 4},
|
|
},
|
|
func(c *qt.C, headers string) {
|
|
c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
|
|
c.Assert(headers, qt.Contains, "Max-Forwards: 10")
|
|
c.Assert(headers, qt.Contains, "X-Int: 32")
|
|
c.Assert(headers, qt.Contains, "X-Templ: a")
|
|
c.Assert(headers, qt.Contains, "X-Multiple: a")
|
|
c.Assert(headers, qt.Contains, "X-Multiple: b")
|
|
c.Assert(headers, qt.Contains, "X-Multipleint: 3")
|
|
c.Assert(headers, qt.Contains, "X-Multipleint: 4")
|
|
c.Assert(headers, qt.Contains, "User-Agent: Hugo Static Site Generator")
|
|
},
|
|
},
|
|
{
|
|
`Params`,
|
|
maps.Params{
|
|
"Accept-Charset": "utf-8",
|
|
},
|
|
func(c *qt.C, headers string) {
|
|
c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
|
|
},
|
|
},
|
|
{
|
|
`Override User-Agent`,
|
|
map[string]any{
|
|
"User-Agent": "007",
|
|
},
|
|
func(c *qt.C, headers string) {
|
|
c.Assert(headers, qt.Contains, "User-Agent: 007")
|
|
},
|
|
},
|
|
} {
|
|
|
|
c.Run(test.name, func(c *qt.C) {
|
|
|
|
ns := newTestNs()
|
|
|
|
// Setup HTTP test server
|
|
var srv *httptest.Server
|
|
var headers bytes.Buffer
|
|
srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
|
|
c.Assert(r.URL.String(), qt.Equals, "http://gohugo.io/api?foo")
|
|
w.Write([]byte("{}"))
|
|
r.Header.Write(&headers)
|
|
|
|
})
|
|
defer func() { srv.Close() }()
|
|
|
|
testFunc := func(fn func(args ...any) error) {
|
|
defer headers.Reset()
|
|
err := fn("http://example.org/api", "?foo", test.headers)
|
|
|
|
c.Assert(err, qt.IsNil)
|
|
c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0)
|
|
test.assert(c, headers.String())
|
|
}
|
|
|
|
testFunc(func(args ...any) error {
|
|
_, err := ns.GetJSON(args...)
|
|
return err
|
|
})
|
|
testFunc(func(args ...any) error {
|
|
_, err := ns.GetCSV(",", args...)
|
|
return err
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
func TestToURLAndHeaders(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
url, headers := toURLAndHeaders([]any{"https://foo?id=", 32})
|
|
c.Assert(url, qt.Equals, "https://foo?id=32")
|
|
c.Assert(headers, qt.IsNil)
|
|
|
|
url, headers = toURLAndHeaders([]any{"https://foo?id=", 32, map[string]any{"a": "b"}})
|
|
c.Assert(url, qt.Equals, "https://foo?id=32")
|
|
c.Assert(headers, qt.DeepEquals, map[string]any{"a": "b"})
|
|
}
|
|
|
|
func TestParseCSV(t *testing.T) {
|
|
t.Parallel()
|
|
c := qt.New(t)
|
|
|
|
for i, test := range []struct {
|
|
csv []byte
|
|
sep string
|
|
exp string
|
|
err bool
|
|
}{
|
|
{[]byte("a,b,c\nd,e,f\n"), "", "", true},
|
|
{[]byte("a,b,c\nd,e,f\n"), "~/", "", true},
|
|
{[]byte("a,b,c\nd,e,f"), "|", "a,b,cd,e,f", false},
|
|
{[]byte("q,w,e\nd,e,f"), ",", "qwedef", false},
|
|
{[]byte("a|b|c\nd|e|f|g"), "|", "abcdefg", true},
|
|
{[]byte("z|y|c\nd|e|f"), "|", "zycdef", false},
|
|
} {
|
|
msg := qt.Commentf("Test %d: %v", i, test)
|
|
|
|
csv, err := parseCSV(test.csv, test.sep)
|
|
if test.err {
|
|
c.Assert(err, qt.Not(qt.IsNil), msg)
|
|
continue
|
|
}
|
|
c.Assert(err, qt.IsNil, msg)
|
|
|
|
act := ""
|
|
for _, v := range csv {
|
|
act = act + strings.Join(v, "")
|
|
}
|
|
|
|
c.Assert(act, qt.Equals, test.exp, msg)
|
|
}
|
|
}
|