github.com/timestee/gotemplate@v0.0.0-20170505123500-7c22f8f4ddd0/template_test.go (about) 1 // Tests for template 2 3 package main 4 5 import ( 6 "bytes" 7 "go/build" 8 "io/ioutil" 9 "log" 10 "os" 11 "os/exec" 12 "path" 13 "testing" 14 ) 15 16 type TestTemplate struct { 17 title string 18 args string 19 pkg string 20 in string 21 outName string 22 out string 23 } 24 25 const basicTest = `package tt 26 27 import "fmt" 28 29 // template type Set(A) 30 type A int 31 32 type Set struct { a A } 33 func NewSet(a A) A { return A(0) } 34 func NewSizedSet(a A) A { return A(1) } 35 func UtilityFunc1() {} 36 func utilityFunc() {} 37 func (a A) f0() {} 38 func (a *A) F1() {} 39 var AVar1 int 40 var aVar2 int 41 var ( 42 AVar3 int 43 aVar4 int 44 ) 45 ` 46 47 var tests = []TestTemplate{ 48 { 49 title: "Simple test public", 50 args: "MySet(int)", 51 pkg: "main", 52 in: basicTest, 53 outName: "gotemplate_MySet.go", 54 out: `// Code generated by gotemplate. DO NOT EDIT. 55 56 package main 57 58 import "fmt" 59 60 // template type Set(A) 61 62 type MySet struct{ a int } 63 64 func NewMySet(a int) int { return int(0) } 65 func NewSizedMySet(a int) int { return int(1) } 66 func UtilityFunc1MySet() {} 67 func utilityFuncMySet() {} 68 func (a int) f0() {} 69 func (a *int) F1() {} 70 71 var AVar1MySet int 72 var aVar2MySet int 73 var ( 74 AVar3MySet int 75 aVar4MySet int 76 ) 77 `, 78 }, 79 { 80 title: "Simple test private", 81 args: "mySet(float64)", 82 pkg: "main", 83 in: basicTest, 84 outName: "gotemplate_mySet.go", 85 out: `// Code generated by gotemplate. DO NOT EDIT. 86 87 package main 88 89 import "fmt" 90 91 // template type Set(A) 92 93 type mySet struct{ a float64 } 94 95 func newMySet(a float64) float64 { return float64(0) } 96 func newSizedMySet(a float64) float64 { return float64(1) } 97 func utilityFunc1MySet() {} 98 func utilityFuncMySet() {} 99 func (a float64) f0() {} 100 func (a *float64) F1() {} 101 102 var aVar1MySet int 103 var aVar2MySet int 104 var ( 105 aVar3MySet int 106 aVar4MySet int 107 ) 108 `, 109 }, 110 { 111 title: "Test function", 112 args: "Min(int8, func(a int8, b int8) bool { return a < b })", 113 pkg: "main", 114 in: `package tt 115 116 // template type TT(A, Less) 117 type A int 118 func Less(a, b A) { return a < b } 119 120 func TT(a, b A) A { return Less(a, b) } 121 func TTone(a A) A { return !Less(a, b) } 122 `, 123 outName: "gotemplate_Min.go", 124 out: `// Code generated by gotemplate. DO NOT EDIT. 125 126 package main 127 128 // template type TT(A, Less) 129 130 func Min(a, b int8) int8 { 131 return func(a int8, b int8) bool { 132 return a < b 133 }(a, b) 134 } 135 func Minone(a int8) int8 { 136 return !func(a int8, b int8) bool { 137 return a < b 138 }(a, b) 139 } 140 `, 141 }, 142 { 143 title: "Simple Test constants", 144 args: "Vector2(float32, 2)", 145 pkg: "main", 146 in: `package tt 147 148 // template type Vector(A, n) 149 type A float32 150 const n = 3 151 152 type Vector [n]A 153 154 func (v Vector) Add(b Vector) { 155 for i := range v { 156 v += b[i] 157 } 158 } 159 `, 160 outName: "gotemplate_Vector2.go", 161 out: `// Code generated by gotemplate. DO NOT EDIT. 162 163 package main 164 165 // template type Vector(A, n) 166 167 type Vector2 [2]float32 168 169 func (v Vector2) Add(b Vector2) { 170 for i := range v { 171 v += b[i] 172 } 173 } 174 `, 175 }, 176 { 177 title: "Test constants", 178 args: "Matrix22(float32, 2, 2)", 179 pkg: "main", 180 in: `package mat 181 182 // template type Matrix(A, n, m) 183 type A float32 184 185 const ( 186 n, a, b, m = 1, 2, 3, 1 187 ) 188 189 type Matrix [n][m]A 190 191 func (mat Matrix) Add(x Matrix) { 192 for i := range mat { 193 for j := range mat[i] { 194 mat[i][j] += x[i][j] 195 } 196 } 197 } 198 `, 199 outName: "gotemplate_Matrix22.go", 200 out: `// Code generated by gotemplate. DO NOT EDIT. 201 202 package main 203 204 // template type Matrix(A, n, m) 205 206 const ( 207 aMatrix22, bMatrix22 = 2, 3 208 ) 209 210 type Matrix22 [2][2]float32 211 212 func (mat Matrix22) Add(x Matrix22) { 213 for i := range mat { 214 for j := range mat[i] { 215 mat[i][j] += x[i][j] 216 } 217 } 218 } 219 `, 220 }, 221 { 222 title: "Test vars", 223 args: "ProgXX(xx1, xx2, xx3, xx4, xx5, xx6)", 224 pkg: "main", 225 in: `package prog 226 227 // template type Prog(a, b, c, d, e, f) 228 type A float32 229 230 var ( 231 a, z = 1, 2 232 b, n, m, c = 3, 4, 5, 6 233 d = 7 234 ) 235 236 var ( 237 o = 8 238 e = 8 239 ) 240 241 var ( 242 e = 8 243 ) 244 245 var ( 246 oo = 9 247 e = 10 248 ) 249 250 var ( 251 p, f, q = 11, 12, 13 252 ) 253 254 func Prog() int {return a+b+c+d+e+f} 255 `, 256 outName: "gotemplate_ProgXX.go", 257 out: `// Code generated by gotemplate. DO NOT EDIT. 258 259 package main 260 261 // template type Prog(a, b, c, d, e, f) 262 type AProgXX float32 263 264 var ( 265 zProgXX = 2 266 nProgXX, mProgXX = 4, 5 267 ) 268 269 var ( 270 oProgXX = 8 271 ) 272 273 var ( 274 ooProgXX = 9 275 ) 276 277 var ( 278 pProgXX, qProgXX = 11, 13 279 ) 280 281 func ProgXX() int { return xx1 + xx2 + xx3 + xx4 + xx5 + xx6 } 282 `, 283 }, 284 { 285 title: "Test complex type decls", 286 args: "tmpl(int, string, map[string]map[string]chan int, float32, rune, chan []string)", 287 pkg: "main", 288 in: `package tt 289 290 // template type TMPL(A, B, C, D, E, F) 291 type A int 292 293 type TMPL struct { 294 a A 295 b B 296 c C 297 d D 298 e E 299 f F 300 } 301 302 type ImportantType bool 303 304 type ( 305 ImportantType1 int 306 B struct { 307 v map[int][][][]rune 308 } 309 importantType2 map[int]int 310 C chan struct { 311 x []string 312 } 313 ) 314 315 type ( 316 D rune 317 importantType3 struct{} 318 E string 319 F map[string]int 320 ) 321 `, 322 outName: "gotemplate_tmpl.go", 323 out: `// Code generated by gotemplate. DO NOT EDIT. 324 325 package main 326 327 // template type TMPL(A, B, C, D, E, F) 328 329 type tmpl struct { 330 a int 331 b string 332 c map[string]map[string]chan int 333 d float32 334 e rune 335 f chan []string 336 } 337 338 type importantTypeTmpl bool 339 340 type ( 341 importantType1Tmpl int 342 343 importantType2Tmpl map[int]int 344 ) 345 346 type ( 347 importantType3Tmpl struct{} 348 ) 349 `, 350 }, 351 } 352 353 func testTemplate(t *testing.T, test *TestTemplate) { 354 // Disable logging 355 log.SetOutput(ioutil.Discard) 356 357 // Make temporary directory 358 dir, err := ioutil.TempDir("", "gotemplate_test") 359 if err != nil { 360 t.Fatalf("Failed to make temp dir: %v", err) 361 } 362 defer func() { 363 err := os.RemoveAll(dir) 364 if err != nil { 365 t.Logf("Failed to remove temp dir: %v", err) 366 } 367 }() 368 369 // Make subdirectories 370 src := path.Join(dir, "src") 371 err = os.Mkdir(src, 0700) 372 if err != nil { 373 t.Fatalf("Failed to make dir %q: %v", src, err) 374 } 375 input := path.Join(src, "input") 376 err = os.Mkdir(input, 0700) 377 if err != nil { 378 t.Fatalf("Failed to make dir %q: %v", input, err) 379 } 380 output := path.Join(src, "output") 381 err = os.Mkdir(output, 0700) 382 if err != nil { 383 t.Fatalf("Failed to make dir %q: %v", output, err) 384 } 385 386 // Change directory to output directory 387 cwd, err := os.Getwd() 388 if err != nil { 389 t.Fatalf("Failed to read cwd: %v", err) 390 } 391 err = os.Chdir(output) 392 if err != nil { 393 t.Fatalf("Failed to cd %q dir: %v", output, err) 394 } 395 defer func() { 396 err := os.Chdir(cwd) 397 if err != nil { 398 t.Logf("Failed to change back to cwd: %v", err) 399 } 400 }() 401 402 // Set GOPATH to directory 403 build.Default.GOPATH = dir 404 405 // Write template input 406 tmpl := path.Join(input, "main.go") 407 err = ioutil.WriteFile(tmpl, []byte(test.in), 0600) 408 if err != nil { 409 t.Fatalf("Failed to write %q: %v", tmpl, err) 410 } 411 412 // Write main.go for output 413 main := path.Join(output, "main.go") 414 err = ioutil.WriteFile(main, []byte("package main"), 0600) 415 if err != nil { 416 t.Fatalf("Failed to write %q: %v", main, err) 417 } 418 419 // Instantiate template 420 template := newTemplate(output, "input", test.args) 421 template.instantiate() 422 423 // Check output 424 expectedFile := path.Join(output, test.outName) 425 actualBytes, err := ioutil.ReadFile(expectedFile) 426 if err != nil { 427 t.Fatalf("Failed to read %q: %v", expectedFile, err) 428 } 429 actual := string(actualBytes) 430 if actual != test.out { 431 t.Errorf(`Output is wrong 432 Got 433 ------------- 434 %s 435 ------------- 436 Expected 437 ------------- 438 %s 439 ------------- 440 `, actual, test.out) 441 actualFile := expectedFile + ".actual" 442 err = ioutil.WriteFile(actualFile, []byte(test.out), 0600) 443 if err != nil { 444 t.Fatalf("Failed to write %q: %v", actualFile, err) 445 } 446 cmd := exec.Command("diff", "-u", actualFile, expectedFile) 447 var out bytes.Buffer 448 cmd.Stdout = &out 449 cmd.Stderr = &out 450 _ = cmd.Run() 451 t.Errorf("Diff\n----\n%s", out.String()) 452 } 453 454 } 455 456 func TestSub(t *testing.T) { 457 fatalf = func(format string, args ...interface{}) { 458 t.Fatalf(format, args...) 459 } 460 for i := range tests { 461 t.Logf("Test[%d] %q", i, tests[i].title) 462 testTemplate(t, &tests[i]) 463 } 464 }