mirror of https://github.com/jlelse/GoBlog
Some performance and memory improvements
This commit is contained in:
parent
48f2ac888b
commit
763188169f
22
cache.go
22
cache.go
|
@ -24,14 +24,12 @@ const (
|
|||
type cache struct {
|
||||
g singleflight.Group
|
||||
c *ristretto.Cache
|
||||
cfg *configCache
|
||||
}
|
||||
|
||||
func (a *goBlog) initCache() (err error) {
|
||||
a.cache = &cache{
|
||||
cfg: a.cfg.Cache,
|
||||
}
|
||||
if a.cache.cfg != nil && !a.cache.cfg.Enable {
|
||||
a.cache = &cache{}
|
||||
if a.cfg.Cache != nil && !a.cfg.Cache.Enable {
|
||||
// Cache disabled
|
||||
return nil
|
||||
}
|
||||
a.cache.c, err = ristretto.NewCache(&ristretto.Config{
|
||||
|
@ -50,13 +48,8 @@ func cacheLoggedIn(next http.Handler) http.Handler {
|
|||
|
||||
func (a *goBlog) cacheMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if a.cache.c == nil {
|
||||
// No cache configured
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
// Do checks
|
||||
if !cacheable(r) {
|
||||
if a.cache.c == nil || !cacheable(r) {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
@ -79,7 +72,7 @@ func (a *goBlog) cacheMiddleware(next http.Handler) http.Handler {
|
|||
})
|
||||
ci := cacheInterface.(*cacheItem)
|
||||
// copy and set headers
|
||||
a.cache.setHeaders(w, ci)
|
||||
a.setCacheHeaders(w, ci)
|
||||
// check conditional request
|
||||
if ifNoneMatchHeader := r.Header.Get("If-None-Match"); ifNoneMatchHeader != "" && ifNoneMatchHeader == ci.eTag {
|
||||
// send 304
|
||||
|
@ -129,7 +122,7 @@ func cacheKey(r *http.Request) string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
func (c *cache) setHeaders(w http.ResponseWriter, cache *cacheItem) {
|
||||
func (a *goBlog) setCacheHeaders(w http.ResponseWriter, cache *cacheItem) {
|
||||
// Copy headers
|
||||
for k, v := range cache.header.Clone() {
|
||||
w.Header()[k] = v
|
||||
|
@ -141,7 +134,8 @@ func (c *cache) setHeaders(w http.ResponseWriter, cache *cacheItem) {
|
|||
if cache.expiration != 0 {
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,stale-while-revalidate=%d", cache.expiration, cache.expiration))
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,s-max-age=%d,stale-while-revalidate=%d", c.cfg.Expiration, c.cfg.Expiration/3, c.cfg.Expiration))
|
||||
exp := a.cfg.Cache.Expiration
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,s-max-age=%d,stale-while-revalidate=%d", exp, exp/3, exp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
"gopkg.in/yaml.v3"
|
||||
ws "nhooyr.io/websocket"
|
||||
|
@ -71,9 +72,11 @@ func (a *goBlog) createMarkdownPreview(blog string, markdown []byte) (rendered [
|
|||
p.RenderedTitle = a.renderMdTitle(t)
|
||||
}
|
||||
// Render post
|
||||
var hb htmlBuilder
|
||||
a.renderEditorPreview(&hb, a.cfg.Blogs[blog], p)
|
||||
rendered = hb.Bytes()
|
||||
buf := bufferpool.Get()
|
||||
hb := newHtmlBuilder(buf)
|
||||
a.renderEditorPreview(hb, a.cfg.Blogs[blog], p)
|
||||
rendered = buf.Bytes()
|
||||
bufferpool.Put(buf)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -61,7 +61,7 @@ require (
|
|||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
nhooyr.io/websocket v1.8.7
|
||||
tailscale.com v1.20.2
|
||||
tailscale.com v1.20.3
|
||||
// main
|
||||
willnorris.com/go/microformats v1.1.2-0.20210827044458-ff2a6ae41971
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -823,8 +823,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
|
|||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78 h1:SqYE5+A2qvRhErbsXFfUEUmpWEKxxRSMgGLkvRAFOV4=
|
||||
tailscale.com v1.20.2 h1:Vk6SVGmczDFSx+PYjbKMa8gIC9Y9Rq+vT1XoZni+fkA=
|
||||
tailscale.com v1.20.2/go.mod h1:kjVy3ji2OH5lZhPLIIRacoY3CN4Bo3Yyb2mtoM8nfJ4=
|
||||
tailscale.com v1.20.3 h1:C3g2AgmQaOi0YT5dAal9mslugPXMxwj0EXY7YfL2QrA=
|
||||
tailscale.com v1.20.3/go.mod h1:kjVy3ji2OH5lZhPLIIRacoY3CN4Bo3Yyb2mtoM8nfJ4=
|
||||
willnorris.com/go/microformats v1.1.2-0.20210827044458-ff2a6ae41971 h1:b4juh5znIpBA1KnzHMP0UB4Cs+3/0b0XfchkWE81FXw=
|
||||
willnorris.com/go/microformats v1.1.2-0.20210827044458-ff2a6ae41971/go.mod h1:kvVnWrkkEscVAIITCEoiTX66Hcyg59C7q0E49mb9TJ0=
|
||||
willnorris.com/go/webmention v0.0.0-20211028201829-b0044f1a24d0 h1:3/ozQ2qGZat82ON3AYMTot3gCg/vU7tgn/LYSJbkVPM=
|
||||
|
|
26
markdown.go
26
markdown.go
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"io"
|
||||
|
||||
marktag "git.jlel.se/jlelse/goldmark-mark"
|
||||
chromahtml "github.com/alecthomas/chroma/formatters/html"
|
||||
|
@ -15,6 +16,7 @@ import (
|
|||
"github.com/yuin/goldmark/renderer"
|
||||
"github.com/yuin/goldmark/renderer/html"
|
||||
"github.com/yuin/goldmark/util"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
)
|
||||
|
||||
func (a *goBlog) initMarkdown() {
|
||||
|
@ -76,13 +78,20 @@ func (a *goBlog) initMarkdown() {
|
|||
}
|
||||
|
||||
func (a *goBlog) renderMarkdown(source string, absoluteLinks bool) (rendered []byte, err error) {
|
||||
var buffer bytes.Buffer
|
||||
if absoluteLinks {
|
||||
err = a.absoluteMd.Convert([]byte(source), &buffer)
|
||||
} else {
|
||||
err = a.md.Convert([]byte(source), &buffer)
|
||||
buffer := bufferpool.Get()
|
||||
a.renderMarkdownToWriter(buffer, source, absoluteLinks)
|
||||
rendered = buffer.Bytes()
|
||||
bufferpool.Put(buffer)
|
||||
return
|
||||
}
|
||||
return buffer.Bytes(), err
|
||||
|
||||
func (a *goBlog) renderMarkdownToWriter(w io.Writer, source string, absoluteLinks bool) (err error) {
|
||||
if absoluteLinks {
|
||||
err = a.absoluteMd.Convert([]byte(source), w)
|
||||
} else {
|
||||
err = a.md.Convert([]byte(source), w)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *goBlog) renderMarkdownAsHTML(source string, absoluteLinks bool) (rendered template.HTML, err error) {
|
||||
|
@ -113,8 +122,9 @@ func (a *goBlog) renderMdTitle(s string) string {
|
|||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
err := a.titleMd.Convert([]byte(s), &buffer)
|
||||
buffer := bufferpool.Get()
|
||||
defer bufferpool.Put(buffer)
|
||||
err := a.titleMd.Convert([]byte(s), buffer)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package bufferpool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
var poolMutex sync.Mutex
|
||||
|
||||
func Get() *bytes.Buffer {
|
||||
poolMutex.Lock()
|
||||
defer poolMutex.Unlock()
|
||||
return bufferPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func Put(bufs ...*bytes.Buffer) {
|
||||
poolMutex.Lock()
|
||||
defer poolMutex.Unlock()
|
||||
for _, buf := range bufs {
|
||||
buf.Reset()
|
||||
bufferPool.Put(buf)
|
||||
}
|
||||
}
|
21
render.go
21
render.go
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -9,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
)
|
||||
|
||||
|
@ -33,9 +33,12 @@ func (a *goBlog) initRendering() error {
|
|||
"html": wrapStringAsHTML,
|
||||
// Code based rendering
|
||||
"tor": func(rd *renderData) template.HTML {
|
||||
var hb htmlBuilder
|
||||
a.renderTorNotice(&hb, rd)
|
||||
return hb.html()
|
||||
buf := bufferpool.Get()
|
||||
hb := newHtmlBuilder(buf)
|
||||
a.renderTorNotice(hb, rd)
|
||||
res := template.HTML(buf.String())
|
||||
bufferpool.Put(buf)
|
||||
return res
|
||||
},
|
||||
// Others
|
||||
"dateformat": dateFormat,
|
||||
|
@ -103,16 +106,14 @@ func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, st
|
|||
// Set content type
|
||||
w.Header().Set(contentType, contenttype.HTMLUTF8)
|
||||
// Render template and write minified HTML
|
||||
var templateBuffer bytes.Buffer
|
||||
if err := a.templates[template].ExecuteTemplate(&templateBuffer, template, data); err != nil {
|
||||
buf := bufferpool.Get()
|
||||
defer bufferpool.Put(buf)
|
||||
if err := a.templates[template].ExecuteTemplate(buf, template, data); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(statusCode)
|
||||
if err := a.min.Minify(contenttype.HTML, w, &templateBuffer); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = a.min.Minify(contenttype.HTML, w, buf)
|
||||
}
|
||||
|
||||
func (a *goBlog) renderNew(w http.ResponseWriter, r *http.Request, f func(*htmlBuilder, *renderData), data *renderData) {
|
||||
|
|
16
ui.go
16
ui.go
|
@ -71,7 +71,7 @@ func (a *goBlog) renderBase(hb *htmlBuilder, rd *renderData, title, main func(hb
|
|||
// Announcement
|
||||
if ann := rd.Blog.Announcement; ann != nil && ann.Text != "" {
|
||||
hb.writeElementOpen("div", "id", "announcement", "data-nosnippet", "")
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(ann.Text))
|
||||
_ = a.renderMarkdownToWriter(hb, ann.Text, false)
|
||||
hb.writeElementClose("div")
|
||||
}
|
||||
// Header
|
||||
|
@ -270,7 +270,7 @@ func (a *goBlog) renderSearch(hb *htmlBuilder, rd *renderData) {
|
|||
// Description
|
||||
if sc.Description != "" {
|
||||
titleOrDesc = true
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(sc.Description))
|
||||
_ = a.renderMarkdownToWriter(hb, sc.Description, false)
|
||||
}
|
||||
if titleOrDesc {
|
||||
hb.writeElementOpen("hr")
|
||||
|
@ -381,7 +381,7 @@ func (a *goBlog) renderIndex(hb *htmlBuilder, rd *renderData) {
|
|||
// Description
|
||||
if id.description != "" {
|
||||
titleOrDesc = true
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(id.description))
|
||||
_ = a.renderMarkdownToWriter(hb, id.description, false)
|
||||
}
|
||||
if titleOrDesc {
|
||||
hb.writeElementOpen("hr")
|
||||
|
@ -445,7 +445,7 @@ func (a *goBlog) renderBlogStats(hb *htmlBuilder, rd *renderData) {
|
|||
}
|
||||
// Description
|
||||
if bs.Description != "" {
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(bs.Description))
|
||||
_ = a.renderMarkdownToWriter(hb, bs.Description, false)
|
||||
}
|
||||
// Table
|
||||
hb.writeElementOpen("p", "id", "loading", "data-table", bsd.tableUrl)
|
||||
|
@ -663,7 +663,7 @@ func (a *goBlog) renderBlogroll(hb *htmlBuilder, rd *renderData) {
|
|||
// Description
|
||||
if bd.description != "" {
|
||||
hb.writeElementOpen("p")
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(bd.description))
|
||||
_ = a.renderMarkdownToWriter(hb, bd.description, false)
|
||||
hb.writeElementClose("p")
|
||||
}
|
||||
// Download button
|
||||
|
@ -745,7 +745,7 @@ func (a *goBlog) renderContact(hb *htmlBuilder, rd *renderData) {
|
|||
}
|
||||
// Description
|
||||
if cd.description != "" {
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(cd.description))
|
||||
_ = a.renderMarkdownToWriter(hb, cd.description, false)
|
||||
}
|
||||
// Form
|
||||
hb.writeElementOpen("form", "class", "fw p", "method", "post")
|
||||
|
@ -760,7 +760,7 @@ func (a *goBlog) renderContact(hb *htmlBuilder, rd *renderData) {
|
|||
hb.writeElementClose("textarea")
|
||||
// Send
|
||||
if cd.privacy != "" {
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(cd.privacy))
|
||||
_ = a.renderMarkdownToWriter(hb, cd.privacy, false)
|
||||
hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "contactagreesend"))
|
||||
} else {
|
||||
hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "contactsend"))
|
||||
|
@ -837,7 +837,7 @@ func (a *goBlog) renderTaxonomy(hb *htmlBuilder, rd *renderData) {
|
|||
}
|
||||
// Description
|
||||
if trd.taxonomy.Description != "" {
|
||||
hb.writeHtml(a.safeRenderMarkdownAsHTML(trd.taxonomy.Description))
|
||||
_ = a.renderMarkdownToWriter(hb, trd.taxonomy.Description, false)
|
||||
}
|
||||
// List
|
||||
for _, valGroup := range trd.valueGroups {
|
||||
|
|
|
@ -38,7 +38,7 @@ func (a *goBlog) renderSummary(hb *htmlBuilder, bc *configBlog, p *post, typ sum
|
|||
photos := a.photoLinks(p)
|
||||
if typ == photoSummary && len(photos) > 0 {
|
||||
for _, photo := range photos {
|
||||
hb.write(string(a.safeRenderMarkdownAsHTML(fmt.Sprintf("![](%s)", photo))))
|
||||
_ = a.renderMarkdownToWriter(hb, fmt.Sprintf("![](%s)", photo), false)
|
||||
}
|
||||
}
|
||||
// Post meta
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
|
@ -10,7 +9,6 @@ import (
|
|||
|
||||
type htmlBuilder struct {
|
||||
w io.Writer
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func newHtmlBuilder(w io.Writer) *htmlBuilder {
|
||||
|
@ -20,11 +18,8 @@ func newHtmlBuilder(w io.Writer) *htmlBuilder {
|
|||
}
|
||||
|
||||
func (h *htmlBuilder) getWriter() io.Writer {
|
||||
if h.w != nil {
|
||||
return h.w
|
||||
}
|
||||
return &h.buf
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) Write(p []byte) (int, error) {
|
||||
return h.getWriter().Write(p)
|
||||
|
@ -34,22 +29,6 @@ func (h *htmlBuilder) WriteString(s string) (int, error) {
|
|||
return io.WriteString(h.getWriter(), s)
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) Read(p []byte) (int, error) {
|
||||
return h.buf.Read(p)
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) String() string {
|
||||
return h.buf.String()
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) Bytes() []byte {
|
||||
return h.buf.Bytes()
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) html() template.HTML {
|
||||
return template.HTML(h.String())
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) write(s string) {
|
||||
_, _ = h.WriteString(s)
|
||||
}
|
||||
|
|
55
ui_test.go
55
ui_test.go
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
var _ io.Writer = &htmlBuilder{}
|
||||
var _ io.StringWriter = &htmlBuilder{}
|
||||
var _ io.Reader = &htmlBuilder{}
|
||||
|
||||
func Test_renderPostTax(t *testing.T) {
|
||||
app := &goBlog{
|
||||
|
@ -30,13 +29,16 @@ func Test_renderPostTax(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
var hb htmlBuilder
|
||||
app.renderPostTax(&hb, p, app.cfg.Blogs["default"])
|
||||
res := hb.html()
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(string(res)))
|
||||
buf := &bytes.Buffer{}
|
||||
hb := newHtmlBuilder(buf)
|
||||
|
||||
app.renderPostTax(hb, p, app.cfg.Blogs["default"])
|
||||
res := buf.String()
|
||||
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(res))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, template.HTML("<p><strong>Tags</strong>: <a class=\"p-category\" rel=\"tag\" href=\"/tags/bar\">Bar</a>, <a class=\"p-category\" rel=\"tag\" href=\"/tags/foo\">Foo</a></p>"), res)
|
||||
assert.Equal(t, "<p><strong>Tags</strong>: <a class=\"p-category\" rel=\"tag\" href=\"/tags/bar\">Bar</a>, <a class=\"p-category\" rel=\"tag\" href=\"/tags/foo\">Foo</a></p>", res)
|
||||
}
|
||||
|
||||
func Test_renderOldContentWarning(t *testing.T) {
|
||||
|
@ -51,13 +53,16 @@ func Test_renderOldContentWarning(t *testing.T) {
|
|||
Published: "2018-01-01",
|
||||
}
|
||||
|
||||
var hb htmlBuilder
|
||||
app.renderOldContentWarning(&hb, p, app.cfg.Blogs["default"])
|
||||
res := hb.html()
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(string(res)))
|
||||
buf := &bytes.Buffer{}
|
||||
hb := newHtmlBuilder(buf)
|
||||
|
||||
app.renderOldContentWarning(hb, p, app.cfg.Blogs["default"])
|
||||
res := buf.String()
|
||||
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(res))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, template.HTML("<strong class=\"p border-top border-bottom\">⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed.</strong>"), res)
|
||||
assert.Equal(t, "<strong class=\"p border-top border-bottom\">⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed.</strong>", res)
|
||||
}
|
||||
|
||||
func Test_renderInteractions(t *testing.T) {
|
||||
|
@ -112,16 +117,19 @@ func Test_renderInteractions(t *testing.T) {
|
|||
err = app.db.approveWebmentionId(2)
|
||||
require.NoError(t, err)
|
||||
|
||||
var hb htmlBuilder
|
||||
app.renderInteractions(&hb, app.cfg.Blogs["default"], "https://example.com/testpost1")
|
||||
res := hb.html()
|
||||
_, err = goquery.NewDocumentFromReader(strings.NewReader(string(res)))
|
||||
buf := &bytes.Buffer{}
|
||||
hb := newHtmlBuilder(buf)
|
||||
|
||||
app.renderInteractions(hb, app.cfg.Blogs["default"], "https://example.com/testpost1")
|
||||
res := buf.Bytes()
|
||||
|
||||
_, err = goquery.NewDocumentFromReader(bytes.NewReader(res))
|
||||
require.NoError(t, err)
|
||||
|
||||
expected, err := os.ReadFile("testdata/interactionstest.html")
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, template.HTML(expected), res)
|
||||
assert.Equal(t, expected, res)
|
||||
}
|
||||
|
||||
func Test_renderAuthor(t *testing.T) {
|
||||
|
@ -134,11 +142,14 @@ func Test_renderAuthor(t *testing.T) {
|
|||
_ = app.initDatabase(false)
|
||||
app.initComponents(false)
|
||||
|
||||
var hb htmlBuilder
|
||||
app.renderAuthor(&hb)
|
||||
res := hb.html()
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(string(res)))
|
||||
buf := &bytes.Buffer{}
|
||||
hb := newHtmlBuilder(buf)
|
||||
|
||||
app.renderAuthor(hb)
|
||||
res := buf.String()
|
||||
|
||||
_, err := goquery.NewDocumentFromReader(strings.NewReader(res))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, template.HTML("<div class=\"p-author h-card hide\"><data class=\"u-photo\" value=\"https://example.com/picture.jpg\"></data><a class=\"p-name u-url\" rel=\"me\" href=\"/\">John Doe</a></div>"), res)
|
||||
assert.Equal(t, "<div class=\"p-author h-card hide\"><data class=\"u-photo\" value=\"https://example.com/picture.jpg\"></data><a class=\"p-name u-url\" rel=\"me\" href=\"/\">John Doe</a></div>", res)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue