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 }