mirror of
https://github.com/gohugoio/hugo.git
synced 2025-02-01 13:50:54 +00:00
f1fec88c30
This commit replaces the multuple `bytes.Containts` and `bytes.Replace` with a custom replacer that does one pass through the document and exploits the fact that there are two common prefixes we search for, `src=` and `href=`. This is both faster and consumes less memory. There may be even better algos to use here, but we must leave some room for improvements for future versions. This should also make it possible to solve #816. ``` benchmark old ns/op new ns/op delta BenchmarkAbsUrl 25795 22597 -12.40% BenchmarkXmlAbsUrl 17187 11166 -35.03% benchmark old allocs new allocs delta BenchmarkAbsUrl 60 33 -45.00% BenchmarkXmlAbsUrl 30 16 -46.67% benchmark old bytes new bytes delta BenchmarkAbsUrl 5844 4167 -28.70% BenchmarkXmlAbsUrl 3754 2069 -44.89% ``` Fixes #894
101 lines
4.9 KiB
Go
101 lines
4.9 KiB
Go
package transform
|
||
|
||
import (
|
||
"bytes"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
const H5_JS_CONTENT_DOUBLE_QUOTE = "<!DOCTYPE html><html><head><script src=\"foobar.js\"></script><script src=\"/barfoo.js\"></script></head><body><nav><h1>title</h1></nav><article>content <a href=\"foobar\">foobar</a>. <a href=\"/foobar\">Follow up</a></article></body></html>"
|
||
const H5_JS_CONTENT_SINGLE_QUOTE = "<!DOCTYPE html><html><head><script src='foobar.js'></script><script src='/barfoo.js'></script></head><body><nav><h1>title</h1></nav><article>content <a href='foobar'>foobar</a>. <a href='/foobar'>Follow up</a></article></body></html>"
|
||
const H5_JS_CONTENT_ABS_URL = "<!DOCTYPE html><html><head><script src=\"http://user@host:10234/foobar.js\"></script></head><body><nav><h1>title</h1></nav><article>content <a href=\"https://host/foobar\">foobar</a>. Follow up</article></body></html>"
|
||
const H5_JS_CONTENT_ABS_URL_SCHEMALESS = "<!DOCTYPE html><html><head><script src=\"//host/foobar.js\"></script><script src='//host2/barfoo.js'></head><body><nav><h1>title</h1></nav><article>content <a href=\"//host/foobar\">foobar</a>. <a href='//host2/foobar'>Follow up</a></article></body></html>"
|
||
const CORRECT_OUTPUT_SRC_HREF_DQ = "<!DOCTYPE html><html><head><script src=\"foobar.js\"></script><script src=\"http://base/barfoo.js\"></script></head><body><nav><h1>title</h1></nav><article>content <a href=\"foobar\">foobar</a>. <a href=\"http://base/foobar\">Follow up</a></article></body></html>"
|
||
const CORRECT_OUTPUT_SRC_HREF_SQ = "<!DOCTYPE html><html><head><script src='foobar.js'></script><script src='http://base/barfoo.js'></script></head><body><nav><h1>title</h1></nav><article>content <a href='foobar'>foobar</a>. <a href='http://base/foobar'>Follow up</a></article></body></html>"
|
||
|
||
const H5_XML_CONTENT_ABS_URL = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?><feed xmlns=\"http://www.w3.org/2005/Atom\"><entry><content type=\"html\"><p><a href="/foobar">foobar</a></p> <p>A video: <iframe src='/foo'></iframe></p></content></entry></feed>"
|
||
const CORRECT_OUTPUT_SRC_HREF_IN_XML = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?><feed xmlns=\"http://www.w3.org/2005/Atom\"><entry><content type=\"html\"><p><a href="http://base/foobar">foobar</a></p> <p>A video: <iframe src='http://base/foo'></iframe></p></content></entry></feed>"
|
||
const H5_XML_CONTENT_GUARDED = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?><feed xmlns=\"http://www.w3.org/2005/Atom\"><entry><content type=\"html\"><p><a href="//foobar">foobar</a></p> <p>A video: <iframe src='//foo'></iframe></p></content></entry></feed>"
|
||
|
||
// additional sanity tests for replacements testing
|
||
const REPLACE_1 = "No replacements."
|
||
const REPLACE_2 = "ᚠᛇᚻ ᛒᛦᚦ ᚠᚱᚩᚠᚢᚱ\nᚠᛁᚱᚪ ᚷᛖᚻᚹᛦᛚᚳᚢᛗ"
|
||
|
||
var abs_url_bench_tests = []test{
|
||
{H5_JS_CONTENT_DOUBLE_QUOTE, CORRECT_OUTPUT_SRC_HREF_DQ},
|
||
{H5_JS_CONTENT_SINGLE_QUOTE, CORRECT_OUTPUT_SRC_HREF_SQ},
|
||
{H5_JS_CONTENT_ABS_URL, H5_JS_CONTENT_ABS_URL},
|
||
{H5_JS_CONTENT_ABS_URL_SCHEMALESS, H5_JS_CONTENT_ABS_URL_SCHEMALESS},
|
||
}
|
||
|
||
var xml_abs_url_bench_tests = []test{
|
||
{H5_XML_CONTENT_ABS_URL, CORRECT_OUTPUT_SRC_HREF_IN_XML},
|
||
{H5_XML_CONTENT_GUARDED, H5_XML_CONTENT_GUARDED},
|
||
}
|
||
|
||
var sanity_tests = []test{{REPLACE_1, REPLACE_1}, {REPLACE_2, REPLACE_2}}
|
||
var abs_url_tests = append(abs_url_bench_tests, sanity_tests...)
|
||
var xml_abs_url_tests = append(xml_abs_url_bench_tests, sanity_tests...)
|
||
|
||
func TestChainZeroTransformers(t *testing.T) {
|
||
tr := NewChain()
|
||
in := new(bytes.Buffer)
|
||
out := new(bytes.Buffer)
|
||
if err := tr.Apply(in, out); err != nil {
|
||
t.Errorf("A zero transformer chain returned an error.")
|
||
}
|
||
}
|
||
|
||
func BenchmarkAbsUrl(b *testing.B) {
|
||
absURL, _ := AbsURL("http://base")
|
||
tr := NewChain(absURL...)
|
||
|
||
b.ResetTimer()
|
||
for i := 0; i < b.N; i++ {
|
||
apply(b.Errorf, tr, abs_url_bench_tests)
|
||
}
|
||
}
|
||
|
||
func TestAbsUrl(t *testing.T) {
|
||
absURL, _ := AbsURL("http://base")
|
||
tr := NewChain(absURL...)
|
||
|
||
apply(t.Errorf, tr, abs_url_tests)
|
||
|
||
}
|
||
|
||
func BenchmarkXmlAbsUrl(b *testing.B) {
|
||
absURLInXML, _ := AbsURLInXML("http://base")
|
||
tr := NewChain(absURLInXML...)
|
||
|
||
b.ResetTimer()
|
||
for i := 0; i < b.N; i++ {
|
||
apply(b.Errorf, tr, xml_abs_url_bench_tests)
|
||
}
|
||
}
|
||
|
||
func TestXMLAbsUrl(t *testing.T) {
|
||
absURLInXML, _ := AbsURLInXML("http://base")
|
||
tr := NewChain(absURLInXML...)
|
||
apply(t.Errorf, tr, xml_abs_url_tests)
|
||
}
|
||
|
||
type errorf func(string, ...interface{})
|
||
|
||
func apply(ef errorf, tr chain, tests []test) {
|
||
for _, test := range tests {
|
||
out := new(bytes.Buffer)
|
||
err := tr.Apply(out, strings.NewReader(test.content))
|
||
if err != nil {
|
||
ef("Unexpected error: %s", err)
|
||
}
|
||
if test.expected != string(out.Bytes()) {
|
||
ef("Expected:\n%s\nGot:\n%s", test.expected, string(out.Bytes()))
|
||
}
|
||
}
|
||
}
|
||
|
||
type test struct {
|
||
content string
|
||
expected string
|
||
}
|