package dati /* Copyright (C) 2023 gearsix This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import ( "bytes" "io/ioutil" "os" "path/filepath" "reflect" "strings" "testing" ) const tmplRootGood = `{{.eg}} {{ template "tmplPartialGood" . }}` const tmplPartialGood = `{{.eg}}` const tmplResult = `0 0` const tmplRootBad = `{{ example }}} {{{ template \"tmplPartialBad\" . }}` const tmplPartialBad = `{{{ .example }}` const htmplRootGood = `

{{.eg}} {{ template "htmplPartialGood" . }}

` const htmplPartialGood = `{{.eg}}` const htmplResult = `

0 0

` const htmplRootBad = `{{ example }} {{{ template "htmplPartialBad" . }}` const htmplPartialBad = `{{{ .example2 }}` const mstRootGood = `{{eg}} {{> mstPartialGood}}` const mstPartialGood = `{{eg}}` const mstResult = `0 0` const mstRootBad = `{{> badPartial.mst}}{{#doesnt-exist}}{{/exit}}` const mstPartialBad = `p{{$}}{{ > noexist}` var templateExts = []string{ ".tmpl", "tmpl", "TMPL", ".TMPL", ".htmpl", "htmpl", "HTMPL", ".HTMPL", ".mst", "mst", "MST", ".MST", ".NONE", "-", ".", "", } func TestIsTemplateLanguage(t *testing.T) { for i, ext := range templateExts { var target bool if i < 12 { target = true } is := IsTemplateLanguage(ext) if is != target { t.Fatalf("%t did not return %t", is, target) } } } func TestReadTemplateLanguage(t *testing.T) { for i, ext := range templateExts { var target TemplateLanguage if i < 4 { target = TMPL } else if i < 8 { target = HTMPL } else if i < 12 { target = MST } else { target = "" } if ReadTemplateLangauge(ext) != target { if target == "" { t.Fatalf("%s is not a supported data language", ext) } else { t.Fatalf("%s did not return %s", ext, target) } } } } func validateTemplate(t *testing.T, template Template, templateType string, rootName string, partialNames ...string) { types := map[string]string{ "tmpl": "*template.Template", "htmpl": "*template.Template", "mst": "*mustache.Template", } rt := reflect.TypeOf(template.T).String() if rt != types[templateType] { t.Fatalf("invalid template type '%s' loaded, should be '%s' (%s)", rt, types[templateType], templateType) } if types[templateType] == "*template.T" { var rv []reflect.Value for _, p := range partialNames { rv := reflect.ValueOf(template.T).MethodByName("Lookup").Call([]reflect.Value{reflect.ValueOf(p)}) if rv[0].IsNil() { t.Fatalf("missing defined template '%s'", p) rv = reflect.ValueOf(template.T).MethodByName("DefinedTemplates").Call([]reflect.Value{}) t.Log(rv) } } rv = reflect.ValueOf(template.T).MethodByName("Name").Call([]reflect.Value{}) if rv[0].String() != rootName { t.Fatalf("invalid template name: %s does not match %s", rv[0].String(), rootName) } } } func validateTemplateFile(t *testing.T, template Template, rootPath string, partialPaths ...string) { rType := ReadTemplateLangauge(rootPath) rName := filepath.Base(rootPath) if rType == "mst" { rName = strings.TrimSuffix(rName, filepath.Ext(rName)) } var pNames []string for _, path := range partialPaths { name := filepath.Base(path) if rType == "mst" { name = strings.TrimSuffix(name, filepath.Ext(name)) } pNames = append(pNames, name) } validateTemplate(t, template, rootPath, rName, pNames...) } func TestLoadTemplateFile(t *testing.T) { t.Parallel() tdir := os.TempDir() var goodRoots, goodPartials, badRoots, badPartials []string createFile := func(path string, data string) { if err := ioutil.WriteFile(path, []byte(data), 0666); err != nil { t.Error(err) } } goodRoots = append(goodRoots, tdir+"/goodRoot.tmpl") createFile(goodRoots[len(goodRoots)-1], tmplRootGood) goodPartials = append(goodPartials, tdir+"/goodPartial.tmpl") createFile(goodPartials[len(goodPartials)-1], tmplPartialGood) badRoots = append(badRoots, tdir+"/badRoot.tmpl") createFile(badRoots[len(badRoots)-1], tmplRootBad) badPartials = append(badRoots, tdir+"/badPartials.tmpl") createFile(badPartials[len(badPartials)-1], tmplPartialBad) goodRoots = append(goodRoots, tdir+"/goodRoot.htmpl") createFile(goodRoots[len(goodRoots)-1], htmplRootGood) goodPartials = append(goodPartials, tdir+"/goodPartial.htmpl") createFile(goodPartials[len(goodPartials)-1], htmplPartialGood) badRoots = append(badRoots, tdir+"/badRoot.htmpl") createFile(badRoots[len(badRoots)-1], htmplRootBad) badPartials = append(badRoots, tdir+"/badPartials.htmpl") createFile(badPartials[len(badPartials)-1], htmplPartialBad) goodRoots = append(goodRoots, tdir+"/goodRoot.mst") createFile(goodRoots[len(goodRoots)-1], mstRootGood) goodPartials = append(goodPartials, tdir+"/goodPartial.mst") createFile(goodPartials[len(goodPartials)-1], mstPartialGood) badRoots = append(badRoots, tdir+"/badRoot.mst") createFile(badRoots[len(badRoots)-1], mstRootBad) badPartials = append(badRoots, tdir+"/badPartials.mst") createFile(badPartials[len(badPartials)-1], mstPartialBad) for i, root := range goodRoots { // good root, good partials if template, e := LoadTemplateFile(root, goodPartials[i]); e != nil { t.Fatal(e) } else { validateTemplateFile(t, template, root, goodPartials[i]) } } for i, root := range badRoots { // bad root, good partials if _, e := LoadTemplateFile(root, goodPartials[i]); e == nil { t.Fatalf("no error for bad template with good partials\n") } } for i, root := range badRoots { // bad root, bad partials if _, e := LoadTemplateFile(root, badPartials[i]); e == nil { t.Fatalf("no error for bad template with bad partials\n") } } } func TestLoadTemplateString(t *testing.T) { var err error var template Template var templateType TemplateLanguage testInvalid := func(templateType TemplateLanguage, template Template) { t.Logf("invalid '%s' template managed to load", templateType) if buf, err := template.Execute(""); err == nil { t.Fatalf("invalid '%s' template managed to execute: %s", templateType, buf.String()) } } name := "test" templateType = TMPL if _, err = LoadTemplateString(templateType, name, tmplRootGood, map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil { t.Fatalf("'%s' template failed to load", templateType) } if _, err = LoadTemplateString(templateType, name, tmplRootBad, map[string]string{"tmplPartialGood": tmplPartialGood}); err == nil { testInvalid(templateType, template) } if _, err = LoadTemplateString(templateType, name, tmplRootGood, map[string]string{"tmplPartialGood": tmplPartialBad}); err == nil { testInvalid(templateType, template) } templateType = "htmpl" if template, err = LoadTemplateString(templateType, name, htmplRootGood, map[string]string{"htmplPartialGood": htmplPartialGood}); err != nil { t.Fatalf("'%s' template failed to load", templateType) } if template, err = LoadTemplateString(templateType, name, htmplRootBad, map[string]string{"htmplPartialGood": htmplPartialGood}); err == nil { testInvalid(templateType, template) } if template, err = LoadTemplateString(templateType, name, htmplRootGood, map[string]string{"htmplPartialGood": htmplPartialBad}); err == nil { testInvalid(templateType, template) } templateType = "mst" if template, err = LoadTemplateString(templateType, name, mstRootGood, map[string]string{"mstPartialGood": mstPartialGood}); err != nil { t.Fatalf("'%s' template failed to load", templateType) } if template, err = LoadTemplateString(templateType, name, mstRootBad, map[string]string{"mstPartialGood": mstPartialGood}); err == nil { testInvalid(templateType, template) } if template, err = LoadTemplateString(templateType, name, mstRootGood, map[string]string{"mstPartialGood": mstPartialBad}); err == nil { testInvalid(templateType, template) } } // func TestLoadTemplateString(t *testing.T) {} // This is tested by TestLoadTemplateFile and TestLoadTemplateString func validateExecute(t *testing.T, results string, expect string, e error) { if e != nil { t.Fatal(e) } else if results != expect { t.Fatalf("invalid results: '%s' should match '%s'", results, expect) } } func TestExecute(t *testing.T) { t.Parallel() var err error var tmpl Template var data map[string]interface{} var results bytes.Buffer if tmpl, err = LoadTemplateString("tmpl", "tmplRootGood", tmplRootGood, map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil { t.Skip("setup failure:", err) } if err = LoadData("json", strings.NewReader(good["json"]), &data); err != nil { t.Skip("setup failure:", err) } results, err = tmpl.Execute(data) validateExecute(t, results.String(), tmplResult, err) if tmpl, err = LoadTemplateString("htmpl", "htmplRootGood", htmplRootGood, map[string]string{"htmplPartialGood": htmplPartialGood}); err != nil { t.Skip("setup failure:", err) } if err = LoadData("yaml", strings.NewReader(good["yaml"]), &data); err != nil { t.Skip("setup failure:", err) } results, err = tmpl.Execute(data) validateExecute(t, results.String(), htmplResult, err) if tmpl, err = LoadTemplateString("mst", "mstRootGood", mstRootGood, map[string]string{"mstPartialGood": mstPartialGood}); err != nil { t.Skip("setup failure:", err) } if err = LoadData("toml", strings.NewReader(good["toml"]), &data); err != nil { t.Skip("setup failure:", err) } results, err = tmpl.Execute(data) validateExecute(t, results.String(), mstResult, err) }