dati

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

template_test.go (9780B)


      1 package dati
      2 
      3 /*
      4 Copyright (C) 2021 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 	"os"
     23 	"io/ioutil"
     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 hmplRootGood = `<!DOCTYPE html><html><p>{{.eg}} {{ template "hmplPartialGood" . }}</p></html>`
     37 const hmplPartialGood = `<b>{{.eg}}</b>`
     38 const hmplResult = `<!DOCTYPE html><html><p>0 <b>0</b></p></html>`
     39 const hmplRootBad = `{{ example }} {{{ template "hmplPartialBad" . }}`
     40 const hmplPartialBad = `<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 func TestIsSupportedTemplateLang(t *testing.T) {
     49 	exts := []string{
     50 		".tmpl", "tmpl", "TMPL", ".TMPL",
     51 		".hmpl", "hmpl", "HMPL", ".HMPL",
     52 		".mst", "mst", "MST", ".MST",
     53 		".NONE", "-", ".", "",
     54 	}
     55 
     56 	for i, ext := range exts {
     57 		var target int
     58 		if i < 4 {
     59 			target = 0
     60 		} else if i < 8 {
     61 			target = 1
     62 		} else if i < 12 {
     63 			target = 2
     64 		} else {
     65 			target = -1
     66 		}
     67 
     68 		if IsSupportedTemplateLang(ext) != target {
     69 			if target == -1 {
     70 				t.Fatalf("%s is not a supported data language", ext)
     71 			} else {
     72 				t.Fatalf("%s did not return %s", ext, SupportedTemplateLangs[target])
     73 			}
     74 		}
     75 	}
     76 }
     77 
     78 func validateTemplate(t *testing.T, template Template, templateType string, rootName string, partialNames ...string) {
     79 	types := map[string]string{
     80 		"tmpl": "*template.Template",
     81 		"hmpl": "*template.Template",
     82 		"mst":  "*mustache.Template",
     83 	}
     84 
     85 	rt := reflect.TypeOf(template.T).String()
     86 	if rt != types[templateType] {
     87 		t.Fatalf("invalid template type '%s' loaded, should be '%s' (%s)", rt, types[templateType], templateType)
     88 	}
     89 
     90 	if types[templateType] == "*template.T" {
     91 		var rv []reflect.Value
     92 		for _, p := range partialNames {
     93 			rv := reflect.ValueOf(template.T).MethodByName("Lookup").Call([]reflect.Value{reflect.ValueOf(p)})
     94 			if rv[0].IsNil() {
     95 				t.Fatalf("missing defined template '%s'", p)
     96 				rv = reflect.ValueOf(template.T).MethodByName("DefinedTemplates").Call([]reflect.Value{})
     97 				t.Log(rv)
     98 			}
     99 		}
    100 		rv = reflect.ValueOf(template.T).MethodByName("Name").Call([]reflect.Value{})
    101 		if rv[0].String() != rootName {
    102 			t.Fatalf("invalid template name: %s does not match %s", rv[0].String(), rootName)
    103 		}
    104 	}
    105 }
    106 
    107 func validateTemplateFile(t *testing.T, template Template, rootPath string, partialPaths ...string) {
    108 	rType := getTemplateType(rootPath)
    109 	rName := filepath.Base(rootPath)
    110 	if rType == "mst" {
    111 		rName = strings.TrimSuffix(rName, filepath.Ext(rName))
    112 	}
    113 	var pNames []string
    114 	for _, path := range partialPaths {
    115 		name := filepath.Base(path)
    116 		if rType == "mst" {
    117 			name = strings.TrimSuffix(name, filepath.Ext(name))
    118 		}
    119 		pNames = append(pNames, name)
    120 	}
    121 
    122 	validateTemplate(t, template, rType, rName, pNames...)
    123 }
    124 
    125 func TestLoadTemplateFilepath(t *testing.T) {
    126 	t.Parallel()
    127 
    128 	tdir := os.TempDir()
    129 	var goodRoots, goodPartials, badRoots, badPartials []string
    130 
    131 	createFile := func(path string, data string) {
    132 		if err := ioutil.WriteFile(path, []byte(data), 0666); err != nil {
    133 			t.Error(err)
    134 		}
    135 	}
    136 
    137 	goodRoots = append(goodRoots, tdir+"/goodRoot.tmpl")
    138 	createFile(goodRoots[len(goodRoots)-1], tmplRootGood)
    139 	goodPartials = append(goodPartials, tdir+"/goodPartial.tmpl")
    140 	createFile(goodPartials[len(goodPartials)-1], tmplPartialGood)
    141 	badRoots = append(badRoots, tdir+"/badRoot.tmpl")
    142 	createFile(badRoots[len(badRoots)-1], tmplRootBad)
    143 	badPartials = append(badRoots, tdir+"/badPartials.tmpl")
    144 	createFile(badPartials[len(badPartials)-1], tmplPartialBad)
    145 
    146 	goodRoots = append(goodRoots, tdir+"/goodRoot.hmpl")
    147 	createFile(goodRoots[len(goodRoots)-1], hmplRootGood)
    148 	goodPartials = append(goodPartials, tdir+"/goodPartial.hmpl")
    149 	createFile(goodPartials[len(goodPartials)-1], hmplPartialGood)
    150 	badRoots = append(badRoots, tdir+"/badRoot.hmpl")
    151 	createFile(badRoots[len(badRoots)-1], hmplRootBad)
    152 	badPartials = append(badRoots, tdir+"/badPartials.hmpl")
    153 	createFile(badPartials[len(badPartials)-1], hmplPartialBad)
    154 
    155 	goodRoots = append(goodRoots, tdir+"/goodRoot.mst")
    156 	createFile(goodRoots[len(goodRoots)-1], mstRootGood)
    157 	goodPartials = append(goodPartials, tdir+"/goodPartial.mst")
    158 	createFile(goodPartials[len(goodPartials)-1], mstPartialGood)
    159 	badRoots = append(badRoots, tdir+"/badRoot.mst")
    160 	createFile(badRoots[len(badRoots)-1], mstRootBad)
    161 	badPartials = append(badRoots, tdir+"/badPartials.mst")
    162 	createFile(badPartials[len(badPartials)-1], mstPartialBad)
    163 
    164 	for i, root := range goodRoots { // good root, good partials
    165 		if template, e := LoadTemplateFilepath(root, goodPartials[i]); e != nil {
    166 			t.Fatal(e)
    167 		} else {
    168 			validateTemplateFile(t, template, root, goodPartials[i])
    169 		}
    170 	}
    171 	for i, root := range badRoots { // bad root, good partials
    172 		if _, e := LoadTemplateFilepath(root, goodPartials[i]); e == nil {
    173 			t.Fatalf("no error for bad template with good partials\n")
    174 		}
    175 	}
    176 	for i, root := range badRoots { // bad root, bad partials
    177 		if _, e := LoadTemplateFilepath(root, badPartials[i]); e == nil {
    178 			t.Fatalf("no error for bad template with bad partials\n")
    179 		}
    180 	}
    181 }
    182 
    183 func TestLoadTemplateString(t *testing.T) {
    184 	var err error
    185 	var template Template
    186 	var templateType string
    187 
    188 	testInvalid := func(templateType string, template Template) {
    189 		t.Logf("invalid '%s' template managed to load", templateType)
    190 		if buf, err := template.Execute(""); err == nil {
    191 			t.Fatalf("invalid '%s' template managed to execute: %s", templateType, buf.String())
    192 		}
    193 	}
    194 
    195 	name := "test"
    196 	templateType = "tmpl"
    197 	if _, err = LoadTemplateString(templateType, name, tmplRootGood,
    198 		map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil {
    199 		t.Fatalf("'%s' template failed to load", templateType)
    200 	}
    201 	if _, err = LoadTemplateString(templateType, name, tmplRootBad,
    202 		map[string]string{"tmplPartialGood": tmplPartialGood}); err == nil {
    203 		testInvalid(templateType, template)
    204 	}
    205 	if _, err = LoadTemplateString(templateType, name, tmplRootGood,
    206 		map[string]string{"tmplPartialGood": tmplPartialBad}); err == nil {
    207 		testInvalid(templateType, template)
    208 	}
    209 
    210 	templateType = "hmpl"
    211 	if template, err = LoadTemplateString(templateType, name, hmplRootGood,
    212 		map[string]string{"hmplPartialGood": hmplPartialGood}); err != nil {
    213 		t.Fatalf("'%s' template failed to load", templateType)
    214 	}
    215 	if template, err = LoadTemplateString(templateType, name, hmplRootBad,
    216 		map[string]string{"hmplPartialGood": hmplPartialGood}); err == nil {
    217 		testInvalid(templateType, template)
    218 	}
    219 	if template, err = LoadTemplateString(templateType, name, hmplRootGood,
    220 		map[string]string{"hmplPartialGood": hmplPartialBad}); err == nil {
    221 		testInvalid(templateType, template)
    222 	}
    223 
    224 	templateType = "mst"
    225 	if template, err = LoadTemplateString(templateType, name, mstRootGood,
    226 		map[string]string{"mstPartialGood": mstPartialGood}); err != nil {
    227 		t.Fatalf("'%s' template failed to load", templateType)
    228 	}
    229 	if template, err = LoadTemplateString(templateType, name, mstRootBad,
    230 		map[string]string{"mstPartialGood": mstPartialGood}); err == nil {
    231 		testInvalid(templateType, template)
    232 	}
    233 	if template, err = LoadTemplateString(templateType, name, mstRootGood,
    234 		map[string]string{"mstPartialGood": mstPartialBad}); err == nil {
    235 		testInvalid(templateType, template)
    236 	}
    237 }
    238 
    239 // func TestLoadTemplateString(t *testing.T) {} // This is tested by TestLoadTemplateFilepath and TestLoadTemplateString
    240 
    241 func validateExecute(t *testing.T, results string, expect string, e error) {
    242 	if e != nil {
    243 		t.Fatal(e)
    244 	} else if results != expect {
    245 		t.Fatalf("invalid results: '%s' should match '%s'", results, expect)
    246 	}
    247 }
    248 
    249 func TestExecute(t *testing.T) {
    250 	t.Parallel()
    251 
    252 	var err error
    253 	var tmpl Template
    254 	var data map[string]interface{}
    255 	var results bytes.Buffer
    256 
    257 	if tmpl, err = LoadTemplateString("tmpl", "tmplRootGood", tmplRootGood,
    258 		map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil {
    259 		t.Skip("setup failure:", err)
    260 	}
    261 	if err = LoadData("json", strings.NewReader(good["json"]), &data); err != nil {
    262 		t.Skip("setup failure:", err)
    263 	}
    264 	results, err = tmpl.Execute(data)
    265 	validateExecute(t, results.String(), tmplResult, err)
    266 
    267 	if tmpl, err = LoadTemplateString("hmpl", "hmplRootGood", hmplRootGood,
    268 		map[string]string{"hmplPartialGood": hmplPartialGood}); err != nil {
    269 		t.Skip("setup failure:", err)
    270 	}
    271 	if err = LoadData("yaml", strings.NewReader(good["yaml"]), &data); err != nil {
    272 		t.Skip("setup failure:", err)
    273 	}
    274 	results, err = tmpl.Execute(data)
    275 	validateExecute(t, results.String(), hmplResult, err)
    276 
    277 	if tmpl, err = LoadTemplateString("mst", "mstRootGood", mstRootGood,
    278 		map[string]string{"mstPartialGood": mstPartialGood}); err != nil {
    279 		t.Skip("setup failure:", err)
    280 	}
    281 	if err = LoadData("toml", strings.NewReader(good["toml"]), &data); err != nil {
    282 		t.Skip("setup failure:", err)
    283 	}
    284 	results, err = tmpl.Execute(data)
    285 	validateExecute(t, results.String(), mstResult, err)
    286 }