template_test.go (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 }