From e2e8bcbec34702a27047b91b6b007a15f1fc0797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sat, 7 Oct 2017 16:52:35 +0200 Subject: [PATCH] tpl: Rework the partial test and benchmarks --- tpl/partials/init.go | 2 +- tpl/partials/partials.go | 4 +- tpl/tplimpl/template_funcs_test.go | 148 ++++++++++------------------- 3 files changed, 54 insertions(+), 100 deletions(-) diff --git a/tpl/partials/init.go b/tpl/partials/init.go index eca93783c..b68256a9a 100644 --- a/tpl/partials/init.go +++ b/tpl/partials/init.go @@ -36,7 +36,7 @@ func init() { }, ) - ns.AddMethodMapping(ctx.getCached, + ns.AddMethodMapping(ctx.IncludeCached, []string{"partialCached"}, [][2]string{}, ) diff --git a/tpl/partials/partials.go b/tpl/partials/partials.go index cf89bad37..da131a974 100644 --- a/tpl/partials/partials.go +++ b/tpl/partials/partials.go @@ -88,11 +88,11 @@ func (ns *Namespace) Include(name string, contextList ...interface{}) (interface return "", fmt.Errorf("Partial %q not found", name) } -// getCached executes and caches partial templates. An optional variant +// IncludeCached executes and caches partial templates. An optional variant // string parameter (a string slice actually, but be only use a variadic // argument to make it optional) can be passed so that a given partial can have // multiple uses. The cache is created with name+variant as the key. -func (ns *Namespace) getCached(name string, context interface{}, variant ...string) (interface{}, error) { +func (ns *Namespace) IncludeCached(name string, context interface{}, variant ...string) (interface{}, error) { key := name if len(variant) > 0 { for i := 0; i < len(variant); i++ { diff --git a/tpl/tplimpl/template_funcs_test.go b/tpl/tplimpl/template_funcs_test.go index 04f4464ec..546effdf3 100644 --- a/tpl/tplimpl/template_funcs_test.go +++ b/tpl/tplimpl/template_funcs_test.go @@ -19,6 +19,7 @@ import ( "path/filepath" "reflect" "testing" + "time" "io/ioutil" "log" @@ -31,6 +32,7 @@ import ( "github.com/gohugoio/hugo/i18n" "github.com/gohugoio/hugo/tpl" "github.com/gohugoio/hugo/tpl/internal" + "github.com/gohugoio/hugo/tpl/partials" "github.com/spf13/afero" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" @@ -112,117 +114,72 @@ func TestTemplateFuncsExamples(t *testing.T) { // we have some package cycle issues to solve first. func TestPartialCached(t *testing.T) { t.Parallel() - testCases := []struct { - name string - partial string - tmpl string - variant string - }{ - // name and partial should match between test cases. - {"test1", "{{ .Title }} seq: {{ shuffle (seq 1 20) }}", `{{ partialCached "test1" . }}`, ""}, - {"test1", "{{ .Title }} seq: {{ shuffle (seq 1 20) }}", `{{ partialCached "test1" . "%s" }}`, "header"}, - {"test1", "{{ .Title }} seq: {{ shuffle (seq 1 20) }}", `{{ partialCached "test1" . "%s" }}`, "footer"}, - {"test1", "{{ .Title }} seq: {{ shuffle (seq 1 20) }}", `{{ partialCached "test1" . "%s" }}`, "header"}, - } + + assert := require.New(t) + + partial := `Now: {{ now.UnixNano }}` + name := "testing" var data struct { - Title string - Section string - Params map[string]interface{} } - data.Title = "**BatMan**" - data.Section = "blog" - data.Params = map[string]interface{}{"langCode": "en"} + config := newDepsConfig(viper.New()) - for i, tc := range testCases { - var tmp string - if tc.variant != "" { - tmp = fmt.Sprintf(tc.tmpl, tc.variant) - } else { - tmp = tc.tmpl - } - - config := newDepsConfig(viper.New()) - - config.WithTemplate = func(templ tpl.TemplateHandler) error { - err := templ.AddTemplate("testroot", tmp) - if err != nil { - return err - } - err = templ.AddTemplate("partials/"+tc.name, tc.partial) - if err != nil { - return err - } - - return nil - } - - de, err := deps.New(config) - require.NoError(t, err) - require.NoError(t, de.LoadResources()) - - buf := new(bytes.Buffer) - templ := de.Tmpl.Lookup("testroot") - err = templ.Execute(buf, &data) + config.WithTemplate = func(templ tpl.TemplateHandler) error { + err := templ.AddTemplate("partials/"+name, partial) if err != nil { - t.Fatalf("[%d] error executing template: %s", i, err) + return err } - for j := 0; j < 10; j++ { - buf2 := new(bytes.Buffer) - err := templ.Execute(buf2, nil) - if err != nil { - t.Fatalf("[%d] error executing template 2nd time: %s", i, err) - } + return nil + } - if !reflect.DeepEqual(buf, buf2) { - t.Fatalf("[%d] cached results do not match:\nResult 1:\n%q\nResult 2:\n%q", i, buf, buf2) - } + de, err := deps.New(config) + assert.NoError(err) + assert.NoError(de.LoadResources()) + + ns := partials.New(de) + + res1, err := ns.IncludeCached(name, &data) + assert.NoError(err) + + for j := 0; j < 10; j++ { + time.Sleep(2 * time.Nanosecond) + res2, err := ns.IncludeCached(name, &data) + assert.NoError(err) + + if !reflect.DeepEqual(res1, res2) { + t.Fatalf("cache mismatch") + } + + res3, err := ns.IncludeCached(name, &data, fmt.Sprintf("variant%d", j)) + assert.NoError(err) + + if reflect.DeepEqual(res1, res3) { + t.Fatalf("cache mismatch") } } + } func BenchmarkPartial(b *testing.B) { - config := newDepsConfig(viper.New()) - config.WithTemplate = func(templ tpl.TemplateHandler) error { - err := templ.AddTemplate("testroot", `{{ partial "bench1" . }}`) - if err != nil { - return err - } - err = templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`) - if err != nil { - return err - } - - return nil - } - - de, err := deps.New(config) - require.NoError(b, err) - require.NoError(b, de.LoadResources()) - - buf := new(bytes.Buffer) - tmpl := de.Tmpl.Lookup("testroot") - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := tmpl.Execute(buf, nil); err != nil { - b.Fatalf("error executing template: %s", err) - } - buf.Reset() - } + doBenchmarkPartial(b, func(ns *partials.Namespace) error { + _, err := ns.Include("bench1") + return err + }) } func BenchmarkPartialCached(b *testing.B) { + doBenchmarkPartial(b, func(ns *partials.Namespace) error { + _, err := ns.IncludeCached("bench1", nil) + return err + }) +} + +func doBenchmarkPartial(b *testing.B, f func(ns *partials.Namespace) error) { config := newDepsConfig(viper.New()) config.WithTemplate = func(templ tpl.TemplateHandler) error { - err := templ.AddTemplate("testroot", `{{ partialCached "bench1" . }}`) - if err != nil { - return err - } - err = templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`) + err := templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`) if err != nil { return err } @@ -234,16 +191,13 @@ func BenchmarkPartialCached(b *testing.B) { require.NoError(b, err) require.NoError(b, de.LoadResources()) - buf := new(bytes.Buffer) - tmpl := de.Tmpl.Lookup("testroot") + ns := partials.New(de) - b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - if err := tmpl.Execute(buf, nil); err != nil { + if err := f(ns); err != nil { b.Fatalf("error executing template: %s", err) } - buf.Reset() } }