github.com/valyala/quicktemplate@v1.7.0/parser/parser_test.go (about)

     1  package parser
     2  
     3  import (
     4  	"bytes"
     5  	"go/format"
     6  	"io/ioutil"
     7  	"os"
     8  	"testing"
     9  
    10  	"github.com/valyala/quicktemplate"
    11  )
    12  
    13  func TestParsePackageName(t *testing.T) {
    14  	// empty template
    15  	testParseSuccess(t, ``)
    16  
    17  	// No package name
    18  	testParseSuccess(t, `foobar`)
    19  
    20  	// explicit package name
    21  	testParseSuccess(t, `{% package foobar %}`)
    22  
    23  	// package name with imports
    24  	testParseSuccess(t, `Package: {%
    25  		package foobar
    26  	%}
    27  	import
    28  	{% import "aa/bb/cc" %}
    29  	yet another import
    30  	{% import (
    31  		"xxx.com/aaa"
    32  	) %}`)
    33  
    34  	// invalid package name
    35  	testParseFailure(t, `{% package foo bar %}`)
    36  	testParseFailure(t, `{% package "foobar" %}`)
    37  	testParseFailure(t, `{% package x(foobar) %}`)
    38  
    39  	// multiple package names
    40  	testParseFailure(t, `{% package foo %}{% package bar %}`)
    41  
    42  	// package name not at the top of the template
    43  	testParseFailure(t, `{% import "foo" %}{% package bar %}`)
    44  	testParseFailure(t, `{% func foo() %}{% endfunc %}{% package bar %}`)
    45  	testParseFailure(t, `{% func foo() %}{% package bar %}{% endfunc %}`)
    46  }
    47  
    48  func TestParseOutputFunc(t *testing.T) {
    49  	// func without args
    50  	testParseSuccess(t, `{% func f() %}{%= f() %}{% endfunc %}`)
    51  	testParseSuccess(t, `{% func f() %}{%= x.y.f() %}{% endfunc %}`)
    52  
    53  	// func with args
    54  	testParseSuccess(t, `{% func f() %}{%= f(1, "foo", bar) %}{% endfunc %}`)
    55  	testParseSuccess(t, `{% func f() %}{%= x.y.f(1, "foo", bar) %}{% endfunc %}`)
    56  
    57  	// html modifier (=h)
    58  	testParseSuccess(t, `{% func f() %}{%=h f(1, "foo", bar) %}{% endfunc %}`)
    59  	testParseSuccess(t, `{% func f() %}{%=h x.y.f(1, "foo", bar) %}{% endfunc %}`)
    60  
    61  	// urlencode modifier (=u)
    62  	testParseSuccess(t, `{% func f() %}{%=u f(1, "foo", bar) %}{% endfunc %}`)
    63  	testParseSuccess(t, `{% func f() %}{%=u x.y.f(1, "foo", bar) %}{% endfunc %}`)
    64  	testParseSuccess(t, `{% func f() %}{%=uh f(1, "foo", bar) %}{% endfunc %}`)
    65  	testParseSuccess(t, `{% func f() %}{%=uh x.y.f(1, "foo", bar) %}{% endfunc %}`)
    66  
    67  	// quoted json string modifier (=q)
    68  	testParseSuccess(t, `{% func f() %}{%=q f(1, "foo", bar) %}{% endfunc %}`)
    69  	testParseSuccess(t, `{% func f() %}{%=q x.y.f(1, "foo", bar) %}{% endfunc %}`)
    70  	testParseSuccess(t, `{% func f() %}{%=qh f(1, "foo", bar) %}{% endfunc %}`)
    71  	testParseSuccess(t, `{% func f() %}{%=qh x.y.f(1, "foo", bar) %}{% endfunc %}`)
    72  
    73  	// unquoted json string modifier (=j)
    74  	testParseSuccess(t, `{% func f() %}{%=j f(1, "foo", bar) %}{% endfunc %}`)
    75  	testParseSuccess(t, `{% func f() %}{%=j x.y.f(1, "foo", bar) %}{% endfunc %}`)
    76  	testParseSuccess(t, `{% func f() %}{%=jh f(1, "foo", bar) %}{% endfunc %}`)
    77  	testParseSuccess(t, `{% func f() %}{%=jh x.y.f(1, "foo", bar) %}{% endfunc %}`)
    78  
    79  	// unknown modifier
    80  	testParseFailure(t, `{% func f() %}{%=w f(1, "foo", bar) %}{% endfunc %}`)
    81  	testParseFailure(t, `{% func f() %}{%=ww x.y.f(1, "foo", bar) %}{% endfunc %}`)
    82  	testParseFailure(t, `{% func f() %}{%=wwh f(1, "foo", bar) %}{% endfunc %}`)
    83  	testParseFailure(t, `{% func f() %}{%=wh x.y.f(1, "foo", bar) %}{% endfunc %}`)
    84  }
    85  
    86  func TestParseCat(t *testing.T) {
    87  	// relative paths
    88  	testParseSuccess(t, `{% func a() %}{% cat "parser.go" %}{% endfunc %}`)
    89  	testParseSuccess(t, `{% func a() %}{% cat "./parser.go" %}{% endfunc %}`)
    90  	testParseSuccess(t, `{% func a() %}{% cat "../parser/parser.go" %}{% endfunc %}`)
    91  
    92  	// multi-cat
    93  	testParseSuccess(t, `{% func a() %}{% cat "parser.go" %}{% cat "./parser.go" %}{% endfunc %}`)
    94  
    95  	// non-existing file
    96  	testParseFailure(t, `{% func a() %}{% cat "non-existing-file.go" %}{% endfunc %}`)
    97  
    98  	// non-const string
    99  	testParseFailure(t, `{% func a() %}{% cat "foobar"+".baz" %}{% endfunc %}`)
   100  	testParseFailure(t, `{% func a() %}{% cat foobar %}{% endfunc %}`)
   101  }
   102  
   103  func TestParseUnexpectedValueAfterTag(t *testing.T) {
   104  	// endfunc
   105  	testParseSuccess(t, "{% func a() %}{% endfunc %}")
   106  	testParseFailure(t, "{% func a() %}{% endfunc foo bar %}")
   107  
   108  	// endfor
   109  	testParseSuccess(t, "{% func a() %}{% for %}{% endfor %}{% endfunc %}")
   110  	testParseFailure(t, "{% func a() %}{% for %}{% endfor foo bar %}{% endfunc %}")
   111  
   112  	// endif
   113  	testParseSuccess(t, "{% func a() %}{% if true %}{% endif %}{% endfunc %}")
   114  	testParseFailure(t, "{% func a() %}{% if true %}{% endif foo bar %}{% endfunc %}")
   115  
   116  	// endswitch
   117  	testParseSuccess(t, "{% func a() %}{% switch %}{% case true %}{% endswitch %}{% endfunc %}")
   118  	testParseFailure(t, "{% func a() %}{% switch %}{% case true %}{% endswitch foobar %}{% endfunc %}")
   119  
   120  	// else
   121  	testParseSuccess(t, "{% func a() %}{% if true %}{% else %}{% endif %}{% endfunc %}")
   122  	testParseFailure(t, "{% func a() %}{% if true %}{% else foo bar %}{% endif %}{% endfunc %}")
   123  
   124  	// return
   125  	testParseSuccess(t, "{% func a() %}{% return %}{% endfunc %}")
   126  	testParseFailure(t, "{% func a() %}{% return foobar %}{% endfunc %}")
   127  
   128  	// break
   129  	testParseSuccess(t, "{% func a() %}{% for %}{% break %}{% endfor %}{% endfunc %}")
   130  	testParseFailure(t, "{% func a() %}{% for %}{% break foobar %}{% endfor %}{% endfunc %}")
   131  
   132  	// default
   133  	testParseSuccess(t, "{% func a() %}{% switch %}{% default %}{% endswitch %}{% endfunc %}")
   134  	testParseFailure(t, "{% func a() %}{% switch %}{% default foobar %}{% endswitch %}{% endfunc %}")
   135  }
   136  
   137  func TestParseFPrecFailure(t *testing.T) {
   138  	// negative precision
   139  	testParseFailure(t, "{% func a()%}{%f.-1 1.2 %}{% endfunc %}")
   140  
   141  	// non-numeric precision
   142  	testParseFailure(t, "{% func a()%}{%f.foo 1.2 %}{% endfunc %}")
   143  
   144  	// more than one dot
   145  	testParseFailure(t, "{% func a()%}{%f.1.234 1.2 %}{% endfunc %}")
   146  	testParseFailure(t, "{% func a()%}{%f.1.foo 1.2 %}{% endfunc %}")
   147  }
   148  
   149  func TestParseFPrecSuccess(t *testing.T) {
   150  	// no precision
   151  	testParseSuccess(t, "{% func a()%}{%f 1.2 %}{% endfunc %}")
   152  	testParseSuccess(t, "{% func a()%}{%f= 1.2 %}{% endfunc %}")
   153  
   154  	// precision set
   155  	testParseSuccess(t, "{% func a()%}{%f.1 1.234 %}{% endfunc %}")
   156  	testParseSuccess(t, "{% func a()%}{%f.10= 1.234 %}{% endfunc %}")
   157  
   158  	// missing precision
   159  	testParseSuccess(t, "{% func a()%}{%f. 1.234 %}{% endfunc %}")
   160  	testParseSuccess(t, "{% func a()%}{%f.= 1.234 %}{% endfunc %}")
   161  }
   162  
   163  func TestParseSwitchCaseSuccess(t *testing.T) {
   164  	// single-case switch
   165  	testParseSuccess(t, "{%func a()%}{%switch n%}{%case 1%}aaa{%endswitch%}{%endfunc%}")
   166  
   167  	// multi-case switch
   168  	testParseSuccess(t, "{%func a()%}{%switch%}\n\t  {%case foo()%}\nfoobar{%case bar()%}{%endswitch%}{%endfunc%}")
   169  
   170  	// default statement
   171  	testParseSuccess(t, "{%func a()%}{%switch%}{%default%}{%endswitch%}{%endfunc%}")
   172  
   173  	// switch with break
   174  	testParseSuccess(t, "{%func a()%}{%switch n%}{%case 1%}aaa{%break%}ignore{%endswitch%}{%endfunc%}")
   175  
   176  	// switch on a type
   177  	// See https://github.com/valyala/quicktemplate/issues/77
   178  	testParseSuccess(t, "{%func a()%}{%switch a.(type) %}{% case []string %}aaa{%case int%}bbb{%endswitch%}{%endfunc%}")
   179  
   180  	// complex switch
   181  	testParseSuccess(t, `{%func f()%}{% for %}
   182  		{%switch foo() %}
   183  		The text before the first case
   184  		is converted into a comment
   185  		{%case "foobar" %}
   186  			{% switch %}
   187  			{% case bar() %}
   188  				aaaa{% break %}
   189  				ignore this line
   190  			{% case baz() %}
   191  				bbbb
   192  			{% endswitch %}
   193  		{% case "aaa" %}
   194  			{% for i := 0; i < 10; i++ %}
   195  				foobar
   196  			{% endfor %}
   197  		{% case "qwe", "sdfdf" %}
   198  			aaaa
   199  			{% return %}
   200  		{% case "www" %}
   201  			break from the switch
   202  			{% break %}
   203  		{% default %}
   204  			foobar
   205  		{%endswitch%}
   206  		{% if 42 == 2 %}
   207  			break for the loop
   208  			{% break %}
   209  			ignore this
   210  		{% endif %}
   211  	{% endfor %}{%endfunc%}`)
   212  }
   213  
   214  func TestParseSwitchCaseFailure(t *testing.T) {
   215  	// missing endswitch
   216  	testParseFailure(t, "{%func a()%}{%switch%}{%endfunc%}")
   217  
   218  	// empty switch
   219  	testParseFailure(t, "{%func f()%}{%switch%}{%endswitch%}{%endfunc%}")
   220  
   221  	// case outside switch
   222  	testParseFailure(t, "{%func f()%}{%case%}{%endfunc%}")
   223  
   224  	// the first tag inside switch is non-case
   225  	testParseFailure(t, "{%func f()%}{%switch%}{%return%}{%endswitch%}{%endfunc%}")
   226  	testParseFailure(t, "{%func F()%}{%switch%}{%break%}{%endswitch%}{%endfunc%}")
   227  	testParseFailure(t, "{%func f()%}{%switch 1%}{%return%}{%case 1%}aaa{%endswitch%}{%endfunc%}")
   228  
   229  	// empty case
   230  	testParseFailure(t, "{%func f()%}{%switch%}{%case%}aaa{%endswitch%}{%endfunc%}")
   231  
   232  	// multiple default statements
   233  	testParseFailure(t, "{%func f()%}{%switch%}{%case%}aaa{%default%}bbb{%default%}{%endswitch%}{%endfunc%}")
   234  }
   235  
   236  func TestParseBreakContinueReturn(t *testing.T) {
   237  	testParseSuccess(t, `{% func a() %}{% for %}{% continue %}{% break %}{% return %}{% endfor %}{% endfunc %}`)
   238  	testParseSuccess(t, `{% func a() %}{% for %}
   239  		{% if f1() %}{% continue %}skip this{%s "and this" %}{% endif %}
   240  		{% if f2() %}{% break %}{% for %}{% endfor %}skip this{% endif %}
   241  		{% if f3() %}{% return %}foo{% if f4() %}{% for %}noop{% endfor %}{% endif %}bar skip this{% endif %}
   242  		text
   243  	{% endfor %}{% endfunc %}`)
   244  }
   245  
   246  func TestParseOutputTagSuccess(t *testing.T) {
   247  	// identifier
   248  	testParseSuccess(t, "{%func a()%}{%s foobar %}{%endfunc%}")
   249  
   250  	// method call
   251  	testParseSuccess(t, "{%func a()%}{%s foo.bar.baz(a, b, &A{d:e}) %}{%endfunc%}")
   252  
   253  	// inline function call
   254  	testParseSuccess(t, "{%func f()%}{%s func() string { return foo.bar(baz, aaa) }() %}{%endfunc%}")
   255  
   256  	// map
   257  	testParseSuccess(t, `{%func f()%}{%v map[int]string{1:"foo", 2:"bar"} %}{%endfunc%}`)
   258  
   259  	// jsons-safe string
   260  	testParseSuccess(t, `{% func f() %}{%j "foo\nbar" %}{%endfunc%}`)
   261  
   262  	// url-encoded string
   263  	testParseSuccess(t, `{% func A() %}{%u "fooab" %}{%endfunc%}`)
   264  }
   265  
   266  func TestParseOutputTagFailure(t *testing.T) {
   267  	// empty tag
   268  	testParseFailure(t, "{%func f()%}{%s %}{%endfunc%}")
   269  
   270  	// multiple arguments
   271  	testParseFailure(t, "{%func f()%}{%s a, b %}{%endfunc%}")
   272  
   273  	// invalid code
   274  	testParseFailure(t, "{%func f()%}{%s f(a, %}{%endfunc%}")
   275  	testParseFailure(t, "{%func f()%}{%s Foo{Bar:1 %}{%endfunc%}")
   276  
   277  	// unsupported code
   278  	testParseFailure(t, "{%func f()%}{%s if (a) {} %}{%endfunc%}")
   279  	testParseFailure(t, "{%func f()%}{%s for {} %}{%endfunc%}")
   280  }
   281  
   282  func TestParseTemplateCodeSuccess(t *testing.T) {
   283  	// empty code
   284  	testParseSuccess(t, "{% code %}")
   285  	testParseSuccess(t, "{% func f() %}{% code %}{% endfunc %}")
   286  
   287  	// comment
   288  	testParseSuccess(t, `{% code // foobar %}`)
   289  	testParseSuccess(t, `{% func f() %}{% code // foobar %}{% endfunc %}`)
   290  	testParseSuccess(t, `{% code
   291  		// foo
   292  		// bar
   293  	%}`)
   294  	testParseSuccess(t, `{% func f() %}{% code
   295  		// foo
   296  		// bar
   297  	%}{% endfunc %}`)
   298  	testParseSuccess(t, `{%
   299  		code
   300  		/*
   301  			foo
   302  			bar
   303  		*/
   304  	%}`)
   305  	testParseSuccess(t, `{% func f() %}{%
   306  		code
   307  		/*
   308  			foo
   309  			bar
   310  		*/
   311  	%}{% endfunc %}`)
   312  
   313  	testParseSuccess(t, `{% code var a int %}`)
   314  	testParseSuccess(t, `{% func f() %}{% code var a int %}{% endfunc %}`)
   315  	testParseSuccess(t, `{% func f() %}{% code a := 0 %}{% endfunc %}`)
   316  	testParseSuccess(t, `{% func f() %}{% code type A struct{} %}{% endfunc %}`)
   317  
   318  	// declarations
   319  	testParseSuccess(t, `{%code
   320  		// comment
   321  		type Foo struct {}
   322  		var b = &Foo{}
   323  
   324  		func (f *Foo) Bar() {}
   325  
   326  		// yet another comment
   327  		func Bar(baz int) string {
   328  			return fmt.Sprintf("%d", baz)
   329  		}
   330  	%}`)
   331  }
   332  
   333  func TestParseTemplateCodeFailure(t *testing.T) {
   334  	// import inside the code
   335  	testParseFailure(t, `{% code import "foo" %}`)
   336  
   337  	// incomplete code
   338  	testParseFailure(t, `{% code type A struct { %}`)
   339  	testParseFailure(t, `{% code func F() { %}`)
   340  
   341  	// invalid code
   342  	testParseFailure(t, `{%code { %}`)
   343  	testParseFailure(t, `{%code {} %}`)
   344  	testParseFailure(t, `{%code ( %}`)
   345  	testParseFailure(t, `{%code () %}`)
   346  }
   347  
   348  func TestParseImportSuccess(t *testing.T) {
   349  	// single line import
   350  	testParseSuccess(t, `{% import "github.com/foo/bar" %}`)
   351  
   352  	// multiline import
   353  	testParseSuccess(t, `{% import (
   354  		"foo"
   355  		xxx "bar/baz/aaa"
   356  
   357  		"yyy.com/zzz"
   358  	) %}`)
   359  
   360  	// multiple imports
   361  	testParseSuccess(t, `{% import "foo" %}
   362  		baaas
   363  		{% import (
   364  			"bar"
   365  			"baasd"
   366  		)
   367  		%}
   368  		sddf
   369  	`)
   370  }
   371  
   372  func TestParseImportFailure(t *testing.T) {
   373  	// empty import
   374  	testParseFailure(t, `{%import %}`)
   375  
   376  	// invalid import
   377  	testParseFailure(t, `{%import foo %}`)
   378  
   379  	// non-import code
   380  	testParseFailure(t, `{%import {"foo"} %}`)
   381  	testParseFailure(t, `{%import "foo"
   382  		type A struct {}
   383  	%}`)
   384  	testParseFailure(t, `{%import type a struct{} %}`)
   385  }
   386  
   387  func TestParseFailure(t *testing.T) {
   388  	// unknown tag
   389  	testParseFailure(t, "{% foobar %}")
   390  
   391  	// unexpected tag outside func
   392  	testParseFailure(t, "aaa{% for %}bbb{%endfor%}")
   393  	testParseFailure(t, "{% return %}")
   394  	testParseFailure(t, "{% break %}")
   395  	testParseFailure(t, "{% if 1==1 %}aaa{%endif%}")
   396  	testParseFailure(t, "{%s abc %}")
   397  	testParseFailure(t, "{%v= aaaa(xx) %}")
   398  	testParseFailure(t, "{%= a() %}")
   399  
   400  	// import after func and/or code
   401  	testParseFailure(t, `{%code var i = 0 %}{%import "fmt"%}`)
   402  	testParseFailure(t, `{%func f()%}{%endfunc%}{%import "fmt"%}`)
   403  
   404  	// missing endfunc
   405  	testParseFailure(t, "{%func a() %}aaaa")
   406  
   407  	// empty func name
   408  	testParseFailure(t, "{% func () %}aaa{% endfunc %}")
   409  	testParseFailure(t, "{% func (a int, b string) %}aaa{% endfunc %}")
   410  
   411  	// empty func arguments
   412  	testParseFailure(t, "{% func aaa %}aaa{% endfunc %}")
   413  
   414  	// func with anonymous argument
   415  	testParseFailure(t, "{% func a(x int, string) %}{%endfunc%}")
   416  
   417  	// func with incorrect arguments' list
   418  	testParseFailure(t, "{% func x(foo, bar) %}{%endfunc%}")
   419  	testParseFailure(t, "{% func x(foo bar baz) %}{%endfunc%}")
   420  
   421  	// empty if condition
   422  	testParseFailure(t, "{% func a() %}{% if    %}aaaa{% endif %}{% endfunc %}")
   423  
   424  	// else with content
   425  	testParseFailure(t, "{% func a() %}{% if 3 == 4%}aaaa{% else if 3 ==  5 %}bug{% endif %}{% endfunc %}")
   426  
   427  	// missing endif
   428  	testParseFailure(t, "{%func a() %}{%if foo %}aaa{% endfunc %}")
   429  
   430  	// missing endfor
   431  	testParseFailure(t, "{%func a()%}{%for %}aaa{%endfunc%}")
   432  
   433  	// break outside for
   434  	testParseFailure(t, "{%func a()%}{%break%}{%endfunc%}")
   435  
   436  	// invalid if condition
   437  	testParseFailure(t, "{%func a()%}{%if a = b %}{%endif%}{%endfunc%}")
   438  	testParseFailure(t, "{%func f()%}{%if a { %}{%endif%}{%endfunc%}")
   439  
   440  	// invalid for
   441  	testParseFailure(t, "{%func a()%}{%for a = b %}{%endfor%}{%endfunc%}")
   442  	testParseFailure(t, "{%func f()%}{%for { %}{%endfor%}{%endfunc%}")
   443  
   444  	// invalid code inside func
   445  	testParseFailure(t, "{%func f()%}{%code } %}{%endfunc%}")
   446  	testParseFailure(t, "{%func f()%}{%code { %}{%endfunc%}")
   447  
   448  	// interface inside func
   449  	testParseFailure(t, "{%func f()%}{%interface A { Foo() } %}{%endfunc%}")
   450  
   451  	// interface without name
   452  	testParseFailure(t, "{%interface  { Foo() } %}")
   453  
   454  	// empty interface
   455  	testParseFailure(t, "{% interface Foo {} %}")
   456  
   457  	// invalid interface
   458  	testParseFailure(t, "{%interface aaaa %}")
   459  	testParseFailure(t, "{%interface aa { Foo() %}")
   460  
   461  	// unnamed method
   462  	testParseFailure(t, "{%func (s *S) () %}{%endfunc%}")
   463  
   464  	// empty method arguments
   465  	testParseFailure(t, "{%func (s *S) Foo %}{%endfunc %}")
   466  
   467  	// method with return values
   468  	testParseFailure(t, "{%func (s *S) Foo() string %}{%endfunc%}")
   469  	testParseFailure(t, "{%func (s *S) Bar() (int, string) %}{%endfunc%}")
   470  }
   471  
   472  func TestParserSuccess(t *testing.T) {
   473  	// empty template
   474  	testParseSuccess(t, "")
   475  
   476  	// template without code and funcs
   477  	testParseSuccess(t, "foobar\nbaz")
   478  
   479  	// template with code
   480  	testParseSuccess(t, "{%code var a struct {}\nconst n = 123%}")
   481  
   482  	// import
   483  	testParseSuccess(t, `{%import "foobar"%}`)
   484  	testParseSuccess(t, `{% import (
   485  	"foo"
   486  	"bar"
   487  )%}`)
   488  	testParseSuccess(t, `{%import "foo"%}{%import "bar"%}`)
   489  
   490  	// func
   491  	testParseSuccess(t, "{%func a()%}{%endfunc%}")
   492  
   493  	// func with with condition
   494  	testParseSuccess(t, "{%func a(x bool)%}{%if x%}foobar{%endif%}{%endfunc%}")
   495  
   496  	// func with complex arguments
   497  	testParseSuccess(t, "{%func f(h1, h2 func(x, y int) string, d int)%}{%endfunc%}")
   498  
   499  	// for
   500  	testParseSuccess(t, "{%func a()%}{%for%}aaa{%endfor%}{%endfunc%}")
   501  
   502  	// return
   503  	testParseSuccess(t, "{%func a()%}{%return%}{%endfunc%}")
   504  
   505  	// nested for
   506  	testParseSuccess(t, "{%func a()%}{%for i := 0; i < 10; i++ %}{%for j := 0; j < i; j++%}aaa{%endfor%}{%endfor%}{%endfunc%}")
   507  
   508  	// plain containing arbitrary tags
   509  	testParseSuccess(t, "{%func f()%}{%plain%}This {%endfunc%} is ignored{%endplain%}{%endfunc%}")
   510  
   511  	// comment with arbitrary tags
   512  	testParseSuccess(t, "{%func f()%}{%comment%}This {%endfunc%} is ignored{%endcomment%}{%endfunc%}")
   513  
   514  	// complex if
   515  	testParseSuccess(t, "{%func a()%}{%if n, err := w.Write(p); err != nil %}{%endif%}{%endfunc%}")
   516  
   517  	// complex for
   518  	testParseSuccess(t, "{%func a()%}{%for i, n := 0, len(s); i < n && f(i); i++ %}{%endfor%}{%endfunc%}")
   519  
   520  	// complex code inside func
   521  	testParseSuccess(t, `{%func f()%}{%code
   522  		type A struct{}
   523  		var aa []A
   524  		for i := 0; i < 10; i++ {
   525  			aa = append(aa, &A{})
   526  			if i == 42 {
   527  				break
   528  			}
   529  		}
   530  		return
   531  	%}{%endfunc%}`)
   532  
   533  	// break inside for loop
   534  	testParseSuccess(t, `{%func f()%}{%for%}
   535  		{% if a() %}
   536  			{% break
   537    	 %}
   538  		{% 	
   539  else   
   540  %}
   541  			{% return   %}
   542  		{% endif %}
   543  	{%endfor%}{%endfunc%}`)
   544  
   545  	// interface
   546  	testParseSuccess(t, "{%interface Foo { Bar()\nBaz() } %}")
   547  	testParseSuccess(t, "{%iface Foo { Bar()\nBaz() } %}")
   548  
   549  	// method
   550  	testParseSuccess(t, "{%func (s *S) Foo(bar, baz string) %}{%endfunc%}")
   551  }
   552  
   553  func testParseFailure(t *testing.T, str string) {
   554  	r := bytes.NewBufferString(str)
   555  	w := &bytes.Buffer{}
   556  	if err := Parse(w, r, "qtc-test.qtpl", "memory"); err == nil {
   557  		t.Fatalf("expecting error when parsing %q", str)
   558  	}
   559  }
   560  
   561  func testParseSuccess(t *testing.T, str string) {
   562  	r := bytes.NewBufferString(str)
   563  	w := &bytes.Buffer{}
   564  	if err := Parse(w, r, "qtc-test.qtpl", "memory"); err != nil {
   565  		t.Fatalf("unexpected error when parsing %q: %s", str, err)
   566  	}
   567  }
   568  
   569  func TestParseFile(t *testing.T) {
   570  	currDir, err := os.Getwd()
   571  	if err != nil {
   572  		t.Fatalf("cannot obtain current directory: %s", err)
   573  	}
   574  	if err := os.Chdir("../testdata/qtc"); err != nil {
   575  		t.Fatalf("cannot change directory to `../testdata/qtc`: %s", err)
   576  	}
   577  	defer func() {
   578  		if err := os.Chdir(currDir); err != nil {
   579  			t.Fatalf("cannot change directory to %q: %s", currDir, err)
   580  		}
   581  	}()
   582  
   583  	filename := "test.qtpl"
   584  	f, err := os.Open(filename)
   585  	if err != nil {
   586  		t.Fatalf("cannot open file %q: %s", filename, err)
   587  	}
   588  	defer f.Close()
   589  
   590  	w := quicktemplate.AcquireByteBuffer()
   591  	if err := Parse(w, f, "test.qtpl", "qtc"); err != nil {
   592  		t.Fatalf("unexpected error: %s", err)
   593  	}
   594  	code, err := format.Source(w.B)
   595  	if err != nil {
   596  		t.Fatalf("unexpected error: %s", err)
   597  	}
   598  	quicktemplate.ReleaseByteBuffer(w)
   599  
   600  	expectedFilename := filename + ".expected"
   601  	expectedCode, err := ioutil.ReadFile(expectedFilename)
   602  	if err != nil {
   603  		t.Fatalf("unexpected error: %s", err)
   604  	}
   605  
   606  	if !bytes.Equal(code, expectedCode) {
   607  		if err := ioutil.WriteFile(filename+".generated", code, 0644); err != nil {
   608  			t.Fatal(err)
   609  		}
   610  		t.Fatalf("unexpected code:\n%q\nexpected:\n%q", code, expectedCode)
   611  	}
   612  }
   613  
   614  func TestParseNoLineComments(t *testing.T) {
   615  	const str = "foobar\nbaz"
   616  	r := bytes.NewBufferString(str)
   617  	w := &bytes.Buffer{}
   618  	if err := ParseNoLineComments(w, r, "qtc-test.qtpl", "memory"); err != nil {
   619  		t.Fatalf("unexpected error when parsing %q: %s", str, err)
   620  	}
   621  	if bytes.Contains(w.Bytes(), []byte("//line")) {
   622  		t.Fatal("unexpected line comment")
   623  	}
   624  }