hatmill/benchmark_test.go

106 lines
2.5 KiB
Go

package hatmill_test
import (
"bytes"
"html/template"
"io"
"testing"
h "git.codemonkeysoftware.net/b/hatmill"
he "git.codemonkeysoftware.net/b/hatmill/element"
)
type benchPerson struct {
Name string
FavoriteAnimals []string
}
type benchModel struct {
Title string
Persons []benchPerson
}
var benchData = benchModel{
Title: "People I know",
Persons: []benchPerson{
{Name: "Malter Witty", FavoriteAnimals: []string{"porpoise"}},
{Name: "Perry Moppins", FavoriteAnimals: []string{"penguin"}},
{Name: "Ralbus Fumblemore", FavoriteAnimals: []string{"owl", "cat", "toad"}},
{Name: "Wuce Brayne", FavoriteAnimals: []string{"bat", "robin"}},
},
}
type testingT interface {
Helper()
Error(args ...interface{})
}
func checkError(t testingT, err error) {
t.Helper()
if err != nil {
t.Error(err)
}
}
func stdHtmlTemplate(t testingT) func(testingT, io.Writer, benchModel) {
// hatmill does not pretty-print its output, so neither must we here.
const tpl = `<!DOCTYPE html><html><head><title>{{.Title}}</title></head>` +
`<body>{{range .Persons}}<div><h1>{{.Name}}</h1>` +
`<ul>{{range .FavoriteAnimals}}<li>{{ . }}</li>{{end}}</ul>` +
`</div>{{end}}</body></html>`
compiled, err := template.New("page").Parse(tpl)
checkError(t, err)
return func(t testingT, w io.Writer, model benchModel) {
checkError(t, compiled.Execute(w, model))
}
}
func hatmillTemplate(t testingT, w io.Writer, model benchModel) {
var personHtml h.Terms
for _, p := range model.Persons {
var animalHtml h.Terms
for _, a := range p.FavoriteAnimals {
animalHtml = append(animalHtml, he.Li()(h.Text(a)))
}
personHtml = append(personHtml, he.Div()(
he.H1()(h.Text(p.Name)),
he.Ul()(animalHtml),
))
}
html := he.Html()(
he.Head()(
he.Title()(h.Text(model.Title)),
),
he.Body()(personHtml),
)
_, err := h.WriteDocument(w, html)
checkError(t, err)
}
func TestBenchmarkEquivalence(t *testing.T) {
var stdHtmlOutput bytes.Buffer
stdHtmlTemplate(t)(t, &stdHtmlOutput, benchData)
var hatmillOutput bytes.Buffer
hatmillTemplate(t, &hatmillOutput, benchData)
if stdHtmlOutput.String() != hatmillOutput.String() {
t.Fatalf("Output does not match\nhtml/template: %s\nhatmill: %s",
&stdHtmlOutput, &hatmillOutput)
}
}
func doBenchmark(b *testing.B, tpl func(testingT, io.Writer, benchModel)) {
var buf bytes.Buffer
for i := 0; i < b.N; i++ {
buf.Reset()
tpl(b, &buf, benchData)
}
}
func BenchmarkStdHtmlTemplate(b *testing.B) {
doBenchmark(b, stdHtmlTemplate(b))
}
func BenchmarkHatmill(b *testing.B) {
doBenchmark(b, hatmillTemplate)
}