dati

A Go library/binary to parse & execute data against template langauges.
git clone git://src.gearsix.net/datidati.zip
Log | Files | Refs | Atom | README | LICENSE

template_test.go (raw) (10075B)


   1 package dati
   2 
   3 /*
   4 Copyright (C) 2023 gearsix <gearsix@tuta.io>
   5 
   6 This program is free software: you can redistribute it and/or modify
   7 it under the terms of the GNU General Public License as published by
   8 the Free Software Foundation, either version 3 of the License, or
   9 at your option) any later version.
  10 
  11 This program is distributed in the hope that it will be useful,
  12 but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 GNU General Public License for more details.
  15 
  16 You should have received a copy of the GNU General Public License
  17 along with this program.  If not, see <https://www.gnu.org/licenses/>.
  18 */
  19 
  20 import (
  21 	"bytes"
  22 	"io/ioutil"
  23 	"os"
  24 	"path/filepath"
  25 	"reflect"
  26 	"strings"
  27 	"testing"
  28 )
  29 
  30 const tmplRootGood = `{{.eg}} {{ template "tmplPartialGood" . }}`
  31 const tmplPartialGood = `{{.eg}}`
  32 const tmplResult = `0 0`
  33 const tmplRootBad = `{{ example }}} {{{ template \"tmplPartialBad\" . }}`
  34 const tmplPartialBad = `{{{ .example }}`
  35 
  36 const htmplRootGood = `<!DOCTYPE html><html><p>{{.eg}} {{ template "htmplPartialGood" . }}</p></html>`
  37 const htmplPartialGood = `<b>{{.eg}}</b>`
  38 const htmplResult = `<!DOCTYPE html><html><p>0 <b>0</b></p></html>`
  39 const htmplRootBad = `{{ example }} {{{ template "htmplPartialBad" . }}`
  40 const htmplPartialBad = `<b>{{{ .example2 }}</b>`
  41 
  42 const mstRootGood = `{{eg}} {{> mstPartialGood}}`
  43 const mstPartialGood = `{{eg}}`
  44 const mstResult = `0 0`
  45 const mstRootBad = `{{> badPartial.mst}}{{#doesnt-exist}}{{/exit}}`
  46 const mstPartialBad = `p{{$}}{{ > noexist}`
  47 
  48 var templateExts = []string{
  49 	".tmpl", "tmpl", "TMPL", ".TMPL",
  50 	".htmpl", "htmpl", "HTMPL", ".HTMPL",
  51 	".mst", "mst", "MST", ".MST",
  52 	".NONE", "-", ".", "",
  53 }
  54 
  55 func TestIsTemplateLanguage(t *testing.T) {
  56 	for i, ext := range templateExts {
  57 		var target bool
  58 
  59 		if i < 12 {
  60 			target = true
  61 		}
  62 
  63 		is := IsTemplateLanguage(ext)
  64 		if is != target {
  65 			t.Fatalf("%t did not return %t", is, target)
  66 		}
  67 	}
  68 }
  69 
  70 func TestReadTemplateLanguage(t *testing.T) {
  71 	for i, ext := range templateExts {
  72 		var target TemplateLanguage
  73 
  74 		if i < 4 {
  75 			target = TMPL
  76 		} else if i < 8 {
  77 			target = HTMPL
  78 		} else if i < 12 {
  79 			target = MST
  80 		} else {
  81 			target = ""
  82 		}
  83 
  84 		if ReadTemplateLangauge(ext) != target {
  85 			if target == "" {
  86 				t.Fatalf("%s is not a supported data language", ext)
  87 			} else {
  88 				t.Fatalf("%s did not return %s", ext, target)
  89 			}
  90 		}
  91 	}
  92 }
  93 
  94 func validateTemplate(t *testing.T, template Template, templateType string, rootName string, partialNames ...string) {
  95 	types := map[string]string{
  96 		"tmpl":  "*template.Template",
  97 		"htmpl": "*template.Template",
  98 		"mst":   "*mustache.Template",
  99 	}
 100 
 101 	rt := reflect.TypeOf(template.T).String()
 102 	if rt != types[templateType] {
 103 		t.Fatalf("invalid template type '%s' loaded, should be '%s' (%s)", rt, types[templateType], templateType)
 104 	}
 105 
 106 	if types[templateType] == "*template.T" {
 107 		var rv []reflect.Value
 108 		for _, p := range partialNames {
 109 			rv := reflect.ValueOf(template.T).MethodByName("Lookup").Call([]reflect.Value{reflect.ValueOf(p)})
 110 			if rv[0].IsNil() {
 111 				t.Fatalf("missing defined template '%s'", p)
 112 				rv = reflect.ValueOf(template.T).MethodByName("DefinedTemplates").Call([]reflect.Value{})
 113 				t.Log(rv)
 114 			}
 115 		}
 116 		rv = reflect.ValueOf(template.T).MethodByName("Name").Call([]reflect.Value{})
 117 		if rv[0].String() != rootName {
 118 			t.Fatalf("invalid template name: %s does not match %s", rv[0].String(), rootName)
 119 		}
 120 	}
 121 }
 122 
 123 func validateTemplateFile(t *testing.T, template Template, rootPath string, partialPaths ...string) {
 124 	rType := ReadTemplateLangauge(rootPath)
 125 	rName := filepath.Base(rootPath)
 126 	if rType == "mst" {
 127 		rName = strings.TrimSuffix(rName, filepath.Ext(rName))
 128 	}
 129 	var pNames []string
 130 	for _, path := range partialPaths {
 131 		name := filepath.Base(path)
 132 		if rType == "mst" {
 133 			name = strings.TrimSuffix(name, filepath.Ext(name))
 134 		}
 135 		pNames = append(pNames, name)
 136 	}
 137 
 138 	validateTemplate(t, template, rootPath, rName, pNames...)
 139 }
 140 
 141 func TestLoadTemplateFile(t *testing.T) {
 142 	t.Parallel()
 143 
 144 	tdir := os.TempDir()
 145 	var goodRoots, goodPartials, badRoots, badPartials []string
 146 
 147 	createFile := func(path string, data string) {
 148 		if err := ioutil.WriteFile(path, []byte(data), 0666); err != nil {
 149 			t.Error(err)
 150 		}
 151 	}
 152 
 153 	goodRoots = append(goodRoots, tdir+"/goodRoot.tmpl")
 154 	createFile(goodRoots[len(goodRoots)-1], tmplRootGood)
 155 	goodPartials = append(goodPartials, tdir+"/goodPartial.tmpl")
 156 	createFile(goodPartials[len(goodPartials)-1], tmplPartialGood)
 157 	badRoots = append(badRoots, tdir+"/badRoot.tmpl")
 158 	createFile(badRoots[len(badRoots)-1], tmplRootBad)
 159 	badPartials = append(badRoots, tdir+"/badPartials.tmpl")
 160 	createFile(badPartials[len(badPartials)-1], tmplPartialBad)
 161 
 162 	goodRoots = append(goodRoots, tdir+"/goodRoot.htmpl")
 163 	createFile(goodRoots[len(goodRoots)-1], htmplRootGood)
 164 	goodPartials = append(goodPartials, tdir+"/goodPartial.htmpl")
 165 	createFile(goodPartials[len(goodPartials)-1], htmplPartialGood)
 166 	badRoots = append(badRoots, tdir+"/badRoot.htmpl")
 167 	createFile(badRoots[len(badRoots)-1], htmplRootBad)
 168 	badPartials = append(badRoots, tdir+"/badPartials.htmpl")
 169 	createFile(badPartials[len(badPartials)-1], htmplPartialBad)
 170 
 171 	goodRoots = append(goodRoots, tdir+"/goodRoot.mst")
 172 	createFile(goodRoots[len(goodRoots)-1], mstRootGood)
 173 	goodPartials = append(goodPartials, tdir+"/goodPartial.mst")
 174 	createFile(goodPartials[len(goodPartials)-1], mstPartialGood)
 175 	badRoots = append(badRoots, tdir+"/badRoot.mst")
 176 	createFile(badRoots[len(badRoots)-1], mstRootBad)
 177 	badPartials = append(badRoots, tdir+"/badPartials.mst")
 178 	createFile(badPartials[len(badPartials)-1], mstPartialBad)
 179 
 180 	for i, root := range goodRoots { // good root, good partials
 181 		if template, e := LoadTemplateFile(root, goodPartials[i]); e != nil {
 182 			t.Fatal(e)
 183 		} else {
 184 			validateTemplateFile(t, template, root, goodPartials[i])
 185 		}
 186 	}
 187 	for i, root := range badRoots { // bad root, good partials
 188 		if _, e := LoadTemplateFile(root, goodPartials[i]); e == nil {
 189 			t.Fatalf("no error for bad template with good partials\n")
 190 		}
 191 	}
 192 	for i, root := range badRoots { // bad root, bad partials
 193 		if _, e := LoadTemplateFile(root, badPartials[i]); e == nil {
 194 			t.Fatalf("no error for bad template with bad partials\n")
 195 		}
 196 	}
 197 }
 198 
 199 func TestLoadTemplateString(t *testing.T) {
 200 	var err error
 201 	var template Template
 202 	var templateType TemplateLanguage
 203 
 204 	testInvalid := func(templateType TemplateLanguage, template Template) {
 205 		t.Logf("invalid '%s' template managed to load", templateType)
 206 		if buf, err := template.Execute(""); err == nil {
 207 			t.Fatalf("invalid '%s' template managed to execute: %s", templateType, buf.String())
 208 		}
 209 	}
 210 
 211 	name := "test"
 212 	templateType = TMPL
 213 	if _, err = LoadTemplateString(templateType, name, tmplRootGood,
 214 		map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil {
 215 		t.Fatalf("'%s' template failed to load", templateType)
 216 	}
 217 	if _, err = LoadTemplateString(templateType, name, tmplRootBad,
 218 		map[string]string{"tmplPartialGood": tmplPartialGood}); err == nil {
 219 		testInvalid(templateType, template)
 220 	}
 221 	if _, err = LoadTemplateString(templateType, name, tmplRootGood,
 222 		map[string]string{"tmplPartialGood": tmplPartialBad}); err == nil {
 223 		testInvalid(templateType, template)
 224 	}
 225 
 226 	templateType = "htmpl"
 227 	if template, err = LoadTemplateString(templateType, name, htmplRootGood,
 228 		map[string]string{"htmplPartialGood": htmplPartialGood}); err != nil {
 229 		t.Fatalf("'%s' template failed to load", templateType)
 230 	}
 231 	if template, err = LoadTemplateString(templateType, name, htmplRootBad,
 232 		map[string]string{"htmplPartialGood": htmplPartialGood}); err == nil {
 233 		testInvalid(templateType, template)
 234 	}
 235 	if template, err = LoadTemplateString(templateType, name, htmplRootGood,
 236 		map[string]string{"htmplPartialGood": htmplPartialBad}); err == nil {
 237 		testInvalid(templateType, template)
 238 	}
 239 
 240 	templateType = "mst"
 241 	if template, err = LoadTemplateString(templateType, name, mstRootGood,
 242 		map[string]string{"mstPartialGood": mstPartialGood}); err != nil {
 243 		t.Fatalf("'%s' template failed to load", templateType)
 244 	}
 245 	if template, err = LoadTemplateString(templateType, name, mstRootBad,
 246 		map[string]string{"mstPartialGood": mstPartialGood}); err == nil {
 247 		testInvalid(templateType, template)
 248 	}
 249 	if template, err = LoadTemplateString(templateType, name, mstRootGood,
 250 		map[string]string{"mstPartialGood": mstPartialBad}); err == nil {
 251 		testInvalid(templateType, template)
 252 	}
 253 }
 254 
 255 // func TestLoadTemplateString(t *testing.T) {} // This is tested by TestLoadTemplateFile and TestLoadTemplateString
 256 
 257 func validateExecute(t *testing.T, results string, expect string, e error) {
 258 	if e != nil {
 259 		t.Fatal(e)
 260 	} else if results != expect {
 261 		t.Fatalf("invalid results: '%s' should match '%s'", results, expect)
 262 	}
 263 }
 264 
 265 func TestExecute(t *testing.T) {
 266 	t.Parallel()
 267 
 268 	var err error
 269 	var tmpl Template
 270 	var data map[string]interface{}
 271 	var results bytes.Buffer
 272 
 273 	if tmpl, err = LoadTemplateString("tmpl", "tmplRootGood", tmplRootGood,
 274 		map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil {
 275 		t.Skip("setup failure:", err)
 276 	}
 277 	if err = LoadData("json", strings.NewReader(good["json"]), &data); err != nil {
 278 		t.Skip("setup failure:", err)
 279 	}
 280 	results, err = tmpl.Execute(data)
 281 	validateExecute(t, results.String(), tmplResult, err)
 282 
 283 	if tmpl, err = LoadTemplateString("htmpl", "htmplRootGood", htmplRootGood,
 284 		map[string]string{"htmplPartialGood": htmplPartialGood}); err != nil {
 285 		t.Skip("setup failure:", err)
 286 	}
 287 	if err = LoadData("yaml", strings.NewReader(good["yaml"]), &data); err != nil {
 288 		t.Skip("setup failure:", err)
 289 	}
 290 	results, err = tmpl.Execute(data)
 291 	validateExecute(t, results.String(), htmplResult, err)
 292 
 293 	if tmpl, err = LoadTemplateString("mst", "mstRootGood", mstRootGood,
 294 		map[string]string{"mstPartialGood": mstPartialGood}); err != nil {
 295 		t.Skip("setup failure:", err)
 296 	}
 297 	if err = LoadData("toml", strings.NewReader(good["toml"]), &data); err != nil {
 298 		t.Skip("setup failure:", err)
 299 	}
 300 	results, err = tmpl.Execute(data)
 301 	validateExecute(t, results.String(), mstResult, err)
 302 }