PageRenderTime 35ms CodeModel.GetById 17ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/scalate-core/src/test/scala/org/fusesource/scalate/jade/JadeTemplateTest.scala

http://github.com/scalate/scalate
Scala | 1251 lines | 1177 code | 33 blank | 41 comment | 10 complexity | d983b03253a9ba384b03833d0e68f961 MD5 | raw file
   1/**
   2 * Copyright (C) 2009-2011 the original author or authors.
   3 * See the notice.md file distributed with this work for additional
   4 * information regarding copyright ownership.
   5 *
   6 * Licensed under the Apache License, Version 2.0 (the "License");
   7 * you may not use this file except in compliance with the License.
   8 * You may obtain a copy of the License at
   9 *
  10 *     http://www.apache.org/licenses/LICENSE-2.0
  11 *
  12 * Unless required by applicable law or agreed to in writing, software
  13 * distributed under the License is distributed on an "AS IS" BASIS,
  14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 * See the License for the specific language governing permissions and
  16 * limitations under the License.
  17 */
  18package org.fusesource.scalate
  19package jade
  20
  21import org.fusesource.scalate.scaml._
  22
  23/**
  24 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
  25 */
  26class JadeTemplateTest extends JadeTestSupport {
  27
  28  /////////////////////////////////////////////////////////////////////
  29  //
  30  // Filters
  31  //
  32  /////////////////////////////////////////////////////////////////////
  33
  34  testRender(
  35    "You can use `:` to use filters",
  36    """
  37html
  38  p
  39    :plain
  40          Indentation levels are not enforced in filters.
  41        #{Interpolation} is disabled by default
  42      Last line
  43""", """
  44<html>
  45  <p>
  46        Indentation levels are not enforced in filters.
  47      #{Interpolation} is disabled by default
  48    Last line
  49  </p>
  50</html>
  51""")
  52
  53  testRender(
  54    "Use the `~` filter flag to preserve white space",
  55    """
  56html
  57  p<
  58    :~plain
  59          Indentation levels are not enforced in filters.
  60        #{Interpolation} is disabled by default
  61      Last line
  62""", """
  63<html>
  64  <p>    Indentation levels are not enforced in filters.&#x000A;  #{Interpolation} is disabled by default&#x000A;Last line</p>
  65</html>
  66""")
  67
  68  testRender(
  69    "Use the `&` filter flag to enable sanitizing interpolation",
  70    """
  71html
  72  p
  73    :&plain
  74      I like #{ "<strong>" } cheese
  75""", """
  76<html>
  77  <p>
  78    I like &lt;strong&gt; cheese
  79  </p>
  80</html>
  81""")
  82
  83  testRender(
  84    "Use the `!` filter flag to enable non-sanitizing interpolation",
  85    """
  86html
  87  p
  88    :!plain
  89      I like #{ "<strong>" } cheese #{ "</strong>" }
  90""", """
  91<html>
  92  <p>
  93    I like <strong> cheese </strong>
  94  </p>
  95</html>
  96""")
  97
  98  testRender(
  99    ":javascript filter can be used to safely insert javascript",
 100    """
 101html
 102  head
 103    :javascript
 104      alert("Hello");
 105""", """
 106<html>
 107  <head>
 108    <script type='text/javascript'>
 109      //<![CDATA[
 110        alert("Hello");
 111      //]]>
 112    </script>
 113  </head>
 114</html>
 115""")
 116
 117  testRender(
 118    "filters can be chained",
 119    """
 120pre
 121  :escaped :javascript
 122    alert("Hello");
 123""", """
 124<pre>
 125  &lt;script type='text/javascript'&gt;
 126    //&lt;![CDATA[
 127      alert(&quot;Hello&quot;);
 128    //]]&gt;
 129  &lt;/script&gt;
 130</pre>
 131""")
 132
 133  testRender(
 134    "The markdown filter",
 135    """
 136p
 137  :markdown
 138    Markdown
 139    =======
 140
 141    Hello, *World*
 142""", """
 143<p>
 144  <h1 id = "Markdown">Markdown</h1>
 145
 146  <p>Hello, <em>World</em></p>
 147</p>
 148""")
 149
 150  testRender(
 151    "The `&` flag enables sanitized interpolations.",
 152    """
 153- var flavor = "<raspberry/>"
 154#content
 155  :&markdown
 156    I *really* prefer #{flavor} jam.
 157""", """
 158<div id="content">
 159  <p>I <em>really</em> prefer &lt;raspberry/&gt; jam.</p>
 160</div>
 161""")
 162
 163  testRender(
 164    "The `!` flag enables non-sanitized interpolations.",
 165    """
 166- var flavor = "<raspberry/>"
 167#content
 168  :!markdown
 169    I *really* prefer #{flavor} jam.
 170""", """
 171<div id="content">
 172  <p>I <em>really</em> prefer <raspberry/> jam.</p>
 173</div>
 174""")
 175
 176  /////////////////////////////////////////////////////////////////////
 177  //
 178  // Plain Text
 179  //
 180  /////////////////////////////////////////////////////////////////////
 181
 182  testRender(
 183    "Jade lines starting with | is taken to be plain text, and passed through unmodified. ",
 184    """
 185gee
 186  whiz
 187    | Wow this is cool!
 188""", """
 189<gee>
 190  <whiz>
 191    Wow this is cool!
 192  </whiz>
 193</gee>
 194""")
 195
 196  testRender(
 197    "HTML tags are passed through unmodified as well.",
 198    """
 199p
 200  <div id="blah">Blah!</div>
 201""", """
 202<p>
 203  <div id="blah">Blah!</div>
 204</p>
 205""")
 206
 207  testRender(
 208    "backslash character escapes the first character of a line, allowing use of otherwise interpreted characters as plain text.",
 209    """
 210title
 211  = title
 212  \= title
 213""", """
 214<title>
 215  MyPage
 216  = title
 217</title>
 218""")
 219
 220  testRender(
 221    "Indenting can be disabled with the ScamlOptions.indent option",
 222    """
 223gee
 224  whiz
 225    | Wow this is cool!
 226""", """
 227<gee>
 228<whiz>
 229Wow this is cool!
 230</whiz>
 231</gee>
 232""", { () =>
 233      ScamlOptions.indent = ""
 234    }, { () =>
 235      ScamlOptions.indent = ScamlOptions.DEFAULT_INDENT
 236    })
 237
 238  testRender(
 239    "Newlines can also be disabled with the ScamlOptions.nl option",
 240    """
 241gee
 242  whiz
 243    | Wow this is cool!
 244""", """
 245<gee><whiz>Wow this is cool!</whiz></gee>
 246""", { () =>
 247      ScamlOptions.indent = ""
 248      ScamlOptions.nl = ""
 249    }, { () =>
 250      ScamlOptions.indent = ScamlOptions.DEFAULT_INDENT
 251      ScamlOptions.nl = ScamlOptions.DEFAULT_NL
 252    })
 253
 254  /////////////////////////////////////////////////////////////////////
 255  //
 256  // HTML Elements
 257  //
 258  /////////////////////////////////////////////////////////////////////
 259
 260  testRender(
 261    "a 'tag' can have trailing spaces and nested content",
 262    """
 263html
 264  body
 265""", """
 266<html>
 267  <body></body>
 268</html>
 269""")
 270
 271  testRender(
 272    "'tag' renders a start and end tag",
 273    """
 274html
 275""", """
 276<html></html>
 277""")
 278
 279  testRender(
 280    "'tag text' render start tag, text, and end tag on same line",
 281    """
 282html test
 283""", """
 284<html>test</html>
 285""")
 286
 287  testRender(
 288    "nested tags are rendered indented",
 289    """
 290html
 291  body
 292    | test
 293""", """
 294<html>
 295  <body>
 296    test
 297  </body>
 298</html>
 299""")
 300
 301  testRender(
 302    "single quoted tags can contain special characters",
 303    """
 304'funny.element'.test
 305  | hi
 306""", """
 307<funny.element class="test">
 308  hi
 309</funny.element>
 310""")
 311
 312  testRender(
 313    "'tag = quality' renders a tag with nested content",
 314    """
 315p=quality
 316p = quality
 317""", """
 318<p>scrumptious</p>
 319<p>scrumptious</p>
 320""")
 321
 322  /////////////////////////////////////////////////////////////////////
 323  //
 324  // HTML Elements : Attributes
 325  //
 326  /////////////////////////////////////////////////////////////////////
 327
 328  testRender(
 329    "Brackets represent a Scala hash that is used for specifying the attributes of an element.",
 330    """
 331html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
 332""", """
 333<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"></html>
 334""")
 335
 336  testRender(
 337    "Attribute hashes can also be stretched out over multiple lines to accommodate many attributes.",
 338    """
 339script{:type => "text/javascript",
 340            :src  => "javascripts/script"}
 341""", """
 342<script type="text/javascript" src="javascripts/script"></script>
 343""")
 344
 345  testRender(
 346    "Jade also supports a terser, less Scala-specific attribute syntax based on HTML's attributes.",
 347    """
 348html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")
 349""", """
 350<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"></html>
 351""")
 352
 353  testRender(
 354    "Scala variables can be used by omitting the quotes.",
 355    """
 356a(title=title href=href) Stuff
 357""", """
 358<a title="MyPage" href="http://scalate.fusesource.org">Stuff</a>
 359""")
 360
 361  testRender(
 362    "You can use both syntaxes together.",
 363    """
 364a(title="Hello"){:href => "http://scalate.fusesource.org"} Stuff
 365""", """
 366<a title="Hello" href="http://scalate.fusesource.org">Stuff</a>
 367""")
 368
 369  testRender(
 370    "HTML-style attributes can be stretched across multiple lines just like hash-style attributes",
 371    """
 372script(type="text/javascript"
 373     src="javascripts/script")
 374""", """
 375<script type="text/javascript" src="javascripts/script"></script>
 376""")
 377
 378  testRender(
 379    "Html Attributes can use complex scala expressions",
 380    """
 381div(count={3+4})
 382""", """
 383<div count="7"></div>
 384""")
 385
 386  testRender(
 387    "Html Attributes can use simple scala expressions",
 388    """
 389div(count="#{3+4}")
 390""", """
 391<div count="7"></div>
 392""")
 393
 394  testRender(
 395    "Html Attributes can use scala variables",
 396    """
 397- val count = 5
 398div(count=count)
 399""", """
 400<div count="5"></div>
 401""")
 402
 403  testRender(
 404    "Hash Attributes can use simple scala expressions",
 405    """
 406- val count = 5
 407div{:count=>count}
 408""", """
 409<div count="5"></div>
 410""")
 411
 412  testRender(
 413    "Hash Attributes can use complex scala expressions",
 414    """
 415div{:count=>{3+4}}
 416""", """
 417<div count="7"></div>
 418""")
 419
 420  testRender(
 421    "Enabled boolean attribute in hash style",
 422    """
 423input{:selected => true}
 424""", """
 425<input selected="selected"/>
 426""")
 427
 428  testRender(
 429    "Disabled boolean attribute in hash style",
 430    """
 431input{:selected => false}
 432""", """
 433<input/>
 434""")
 435
 436  testRender(
 437    "Enabled boolean attribute in html style",
 438    """
 439input(selected=true)
 440""", """
 441<input selected="selected"/>
 442""")
 443
 444  testRender(
 445    "Disabled boolean attribute in html style",
 446    """
 447input(selected=false)
 448""", """
 449<input/>
 450""")
 451
 452  testRender(
 453    "Enabled boolean attribute in html style using shorthand",
 454    """
 455input(selected)
 456""", """
 457<input selected="selected"/>
 458""")
 459
 460  testRender(
 461    "Mixing attributes with complex expressions",
 462    """
 463p{ :counter1=>{1 + 2}, :counter2=>10 }
 464""", """
 465<p counter1="3" counter2="10"></p>
 466""")
 467
 468  /////////////////////////////////////////////////////////////////////
 469  //
 470  // HTML Elements : Class and ID: `.` and `#`
 471  //
 472  /////////////////////////////////////////////////////////////////////
 473
 474  testRender(
 475    "`.` and `#` are used as shortcuts to specify the `class` and `id` attributes of an element",
 476    """
 477div#things
 478  span#rice Chicken Fried
 479  p.beans{ :food => "true" } The magical fruit
 480  h1.class.otherclass#id La La La
 481""", """
 482<div id="things">
 483  <span id="rice">Chicken Fried</span>
 484  <p class="beans" food="true">The magical fruit</p>
 485  <h1 id="id" class="class otherclass">La La La</h1>
 486</div>
 487""")
 488
 489  testRender(
 490    "Another `.` and `#` example",
 491    """
 492#content
 493  .articles
 494    .article.title Doogie Howser Comes Out
 495    .article.date 2006-11-05
 496    .article.entry
 497      | Neil Patrick Harris would like to dispel any rumors that he is straight
 498""", """
 499<div id="content">
 500  <div class="articles">
 501    <div class="article title">Doogie Howser Comes Out</div>
 502    <div class="article date">2006-11-05</div>
 503    <div class="article entry">
 504      Neil Patrick Harris would like to dispel any rumors that he is straight
 505    </div>
 506  </div>
 507</div>
 508""")
 509
 510  // Edge cases
 511
 512  testRender(
 513    "'tag#i1#i2' last id specified wins",
 514    """
 515html#i1#i2
 516""", """
 517<html id="i2"></html>
 518""")
 519
 520  testRender(
 521    "'tag.c1' renders a tag with a class",
 522    """
 523html.c1
 524""", """
 525<html class="c1"></html>
 526""")
 527
 528  testRender(
 529    "'tag.c1.c2' renders a tag with multiple classes",
 530    """
 531html.c1.c2
 532""", """
 533<html class="c1 c2"></html>
 534""")
 535
 536  testRender(
 537    "Any css class/name can be used.",
 538    """
 539.my-class
 540._whacky_1
 541""", """
 542<div class="my-class"></div>
 543<div class="_whacky_1"></div>
 544""")
 545
 546  /////////////////////////////////////////////////////////////////////
 547  //
 548  // HTML Elements : Implicit Div Elements
 549  //
 550  /////////////////////////////////////////////////////////////////////
 551
 552  testRender(
 553    "If you only define a class and/or id using `.` or `#`, a div is automatically used.",
 554    """
 555#collection
 556  .item
 557    .description What a cool item!
 558""", """
 559<div id="collection">
 560  <div class="item">
 561    <div class="description">What a cool item!</div>
 562  </div>
 563</div>
 564""")
 565
 566  /////////////////////////////////////////////////////////////////////
 567  //
 568  // HTML Elements : Self-Closing Tags : `/`
 569  //
 570  /////////////////////////////////////////////////////////////////////
 571
 572  testRender(
 573    "The forward slash character, when placed at the end of a tag definition, causes the tag to be self-closed.",
 574    """
 575br/
 576meta{"http-equiv" => "Content-Type", :content => "text/html"}/
 577""", """
 578<br/>
 579<meta http-equiv="Content-Type" content="text/html"/>
 580""")
 581
 582  testRender(
 583    "`meta`, `img`, `link`, `script`, `br`, and `hr` tags are closed by default.",
 584    """
 585br/
 586meta{"http-equiv" => "Content-Type", :content => "text/html"}/
 587""", """
 588<br/>
 589<meta http-equiv="Content-Type" content="text/html"/>
 590""")
 591
 592  /////////////////////////////////////////////////////////////////////
 593  //
 594  // HTML Elements : Whitespace Removal: `>` and `<`
 595  //
 596  /////////////////////////////////////////////////////////////////////
 597
 598  testRender(
 599    "'`<` will remove all whitespace immediately within a tag.",
 600    """
 601blockquote<
 602  div
 603    | Foo!
 604""", """
 605<blockquote><div>
 606  Foo!
 607</div></blockquote>
 608""")
 609
 610  testRender(
 611    "`>` will remove all whitespace surrounding a tag",
 612    """
 613img/
 614img>/
 615img/
 616""", """
 617<img/><img/><img/>
 618""")
 619
 620  testRender(
 621    "`<` will remove all whitespace surrounding a rendered expression",
 622    """
 623p<= "Foo\nBar"
 624""", """
 625<p>Foo
 626Bar</p>
 627""")
 628
 629  testRender(
 630    "'tag><' trims the whitespace surrounding the tag and wrapping nested content'",
 631    """
 632img/
 633pre><
 634  | foo
 635  | bar
 636img/
 637""", """
 638<img/><pre>foo
 639bar</pre><img/>
 640""")
 641
 642  testRender(
 643    "'tag<>' trims the whitespace surrounding the tag and wrapping nested content'",
 644    """
 645img/
 646pre><
 647  | foo
 648  | bar
 649img/
 650""", """
 651<img/><pre>foo
 652bar</pre><img/>
 653""")
 654
 655  /////////////////////////////////////////////////////////////////////
 656  //
 657  // Doctype: !!!
 658  //
 659  /////////////////////////////////////////////////////////////////////
 660  testRender(
 661    "you can have a document type or XML prolog generated automatically by including the characters !!!",
 662    """
 663!!! XML
 664!!!
 665html
 666  head
 667    title Myspace
 668  body
 669    h1 I am the international space station
 670    p Sign my guestbook
 671""", """
 672<?xml version="1.0" encoding="utf-8" ?>
 673<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 674<html>
 675  <head>
 676    <title>Myspace</title>
 677  </head>
 678  <body>
 679    <h1>I am the international space station</h1>
 680    <p>Sign my guestbook</p>
 681  </body>
 682</html>
 683""")
 684
 685  /////////////////////////////////////////////////////////////////////
 686  //
 687  // Comments
 688  //
 689  /////////////////////////////////////////////////////////////////////
 690
 691  testRender(
 692    "The `/`, when placed at the beginning of a line, wraps all text after it in an HTML comment",
 693    """
 694peanutbutterjelly
 695  / This is the peanutbutterjelly element
 696  | I like sandwiches!
 697""", """
 698<peanutbutterjelly>
 699  <!-- This is the peanutbutterjelly element -->
 700  I like sandwiches!
 701</peanutbutterjelly>
 702""")
 703
 704  testRender(
 705    "The `/` can also wrap indented sections of code.",
 706    """
 707/
 708  p This doesn't render...
 709  div
 710    h1 Because it's commented out!
 711""", """
 712<!--
 713  <p>This doesn't render...</p>
 714  <div>
 715    <h1>Because it's commented out!</h1>
 716  </div>
 717-->
 718""")
 719
 720  testRender(
 721    "You can also use Internet Explorer conditional comments by enclosing the condition in square brackets",
 722    """
 723/[if IE]
 724  a{ :href => "http://www.mozilla.com/en-US/firefox/" }
 725    h1 Get Firefox
 726""", """
 727<!--[if IE]>
 728  <a href="http://www.mozilla.com/en-US/firefox/">
 729    <h1>Get Firefox</h1>
 730  </a>
 731<![endif]-->
 732""")
 733
 734  testRender(
 735    "`-#` signifies a silent comment.",
 736    """
 737p foo
 738-# This is a comment
 739p bar
 740""", """
 741<p>foo</p>
 742<p>bar</p>
 743""")
 744
 745  testRender(
 746    "You can also nest text beneath a `-#`",
 747    """
 748p foo
 749-#
 750  This won't be displayed
 751    Nor will this
 752p bar
 753""", """
 754<p>foo</p>
 755<p>bar</p>
 756""")
 757
 758  /////////////////////////////////////////////////////////////////////
 759  //
 760  // Scala Evaluation: Inserting Scala: `=`
 761  //
 762  /////////////////////////////////////////////////////////////////////
 763
 764  testRender(
 765    "`=` is followed by Scala code. This code is evaluated and the output is inserted into the document.",
 766    """
 767p
 768  = List("hi", "there", "reader!").mkString(" ")
 769  = "yo"
 770""", """
 771<p>
 772  hi there reader!
 773  yo
 774</p>
 775""")
 776
 777  testRender(
 778    "`=` can also be used at the end of a tag to insert Scala code within that tag.",
 779    """
 780p= "hello"
 781""", """
 782<p>hello</p>
 783""")
 784
 785  testRender(
 786    "'= var' expressions can acess implicitly bound variables",
 787    """
 788html
 789  body
 790    = context.name
 791""", """
 792<html>
 793  <body>
 794    Hiram
 795  </body>
 796</html>
 797""")
 798
 799  testRender(
 800    "'= var' expressions can access imported variables",
 801    """
 802html
 803  body
 804    = name
 805""", """
 806<html>
 807  <body>
 808    Hiram
 809  </body>
 810</html>
 811""")
 812
 813  testRender(
 814    "= on a NodeSeq is rendered unsanitized",
 815    """
 816-@ val bean:Bean
 817= bean.link
 818""", """
 819<a href="#size-10">red</a>
 820""")
 821
 822  testRender(
 823    "!= a NodeSeq is rendered unsanitized",
 824    """
 825-@ val bean:Bean
 826!= bean.link
 827""", """
 828<a href="#size-10">red</a>
 829""")
 830
 831  // TODO should we do this???
 832  /*
 833  testRender("&= a NodeSeq is rendered sanitized",
 834"""
 835-@ val bean:Bean
 836&= bean.link
 837""","""
 838&lt;a href=&quot;#size-10&quot;&gt;red&lt;/a&gt;
 839""")
 840   */
 841
 842  testRender(
 843    "&= a NodeSeq.toString is rendered sanitized",
 844    """
 845-@ val bean:Bean
 846&= bean.link.toString
 847""", """
 848&lt;a href=&quot;#size-10&quot;&gt;red&lt;/a&gt;
 849""")
 850
 851  /////////////////////////////////////////////////////////////////////
 852  //
 853  // Scala Evaluation: Running Scala: `-`
 854  //
 855  /////////////////////////////////////////////////////////////////////
 856
 857  testRender(
 858    "`-` is followed by Scala code.  The code is evaluated but *not* inserted into the document.",
 859    """
 860- var foo = "hello"
 861- foo += " there"
 862- foo += " you!"
 863p= foo
 864""", """
 865<p>hello there you!</p>
 866""")
 867
 868  testRender(
 869    "`-` is followed by an indented Scala code block.  The code is evaluated but *not* inserted into the document.",
 870    """
 871-
 872  var foo = "hello"
 873      // note: you can use creative indentation in the block
 874      foo += " there"
 875  foo += " you!"
 876p= foo
 877""", """
 878<p>hello there you!</p>
 879""")
 880
 881  /////////////////////////////////////////////////////////////////////
 882  //
 883  // Scala Evaluation: Scala Blocks
 884  //
 885  /////////////////////////////////////////////////////////////////////
 886
 887  testRender(
 888    "Nest block for case statements",
 889    """
 890p
 891  - 2 match
 892    - case 1 =>
 893      = "one"
 894    - case 2 =>
 895      = "two"
 896    - case 3 =>
 897      = "three"
 898""", """
 899<p>
 900  two
 901</p>
 902""")
 903
 904  testRender(
 905    "Nest block for a `for` loop",
 906    """
 907- for(i <- 42 to 46)
 908  p= i
 909p See, I can count!
 910""", """
 911<p>42</p>
 912<p>43</p>
 913<p>44</p>
 914<p>45</p>
 915<p>46</p>
 916<p>See, I can count!</p>
 917""")
 918
 919  testRender(
 920    "Passing partial funtions.",
 921    """
 922p
 923  = List(1,2,3).foldLeft("result: ")
 924    - (a,x)=>
 925      - a+x
 926""", """
 927<p>
 928  result: 123
 929</p>
 930""")
 931
 932  testRender(
 933    "loop constructs don't need {} ",
 934    """
 935ol
 936  li start
 937  - for( i <- 1 to 3 )
 938    - val message = "Hi "+i
 939    li= message
 940  li end
 941""", """
 942<ol>
 943  <li>start</li>
 944  <li>Hi 1</li>
 945  <li>Hi 2</li>
 946  <li>Hi 3</li>
 947  <li>end</li>
 948</ol>
 949""")
 950
 951  testRender(
 952    "if / else constructs",
 953    """
 954- if ( 1==2 )
 955  p alternate reality
 956- else
 957  p still on earth
 958""", """
 959<p>still on earth</p>
 960""")
 961
 962  testRender(
 963    "try / catch constructs",
 964    """
 965- try
 966  p in try
 967  - throw new IllegalStateException()
 968- catch
 969  - case e:IllegalStateException =>
 970    p got the expected error
 971  - case e:Exception =>
 972    p some odd error occurred
 973""", """
 974<p>in try</p>
 975<p>got the expected error</p>
 976""")
 977
 978  /////////////////////////////////////////////////////////////////////
 979  //
 980  // Scala Interpolation: `#{}`
 981  //
 982  /////////////////////////////////////////////////////////////////////
 983
 984  testRender(
 985    "Scala code can be interpolated within plain text using `#{}`",
 986    """
 987p This is #{quality} cake!
 988""", """
 989<p>This is scrumptious cake!</p>
 990""")
 991
 992  testRender(
 993    "Backslashes can be used to escape `#{` strings, but they don't act as escapes anywhere else in the string.",
 994    """
 995p
 996  | A slash make a difference here: \#{name} is set to: \\#{name}
 997  | But is ignored for: \# or \\
 998""", """
 999<p>
1000  A slash make a difference here: #{name} is set to: \Hiram
1001  But is ignored for: \# or \\
1002</p>
1003""")
1004
1005  /////////////////////////////////////////////////////////////////////
1006  //
1007  // Escaping HTML: `&=`
1008  //
1009  /////////////////////////////////////////////////////////////////////
1010
1011  testRender(
1012    "'&= expression' sanitizes the rendered expression",
1013    """
1014&= "I like cheese & crackers"
1015""", """
1016I like cheese &amp; crackers
1017""")
1018
1019  testRender(
1020    "'& text' santizes interpolated expressions",
1021    """
1022& I like #{"cheese & crackers"}
1023""", """
1024I like cheese &amp; crackers
1025""")
1026
1027  testRender(
1028    "'= expression' is sanitized by default",
1029    """
1030= "I feel <strong>!"
1031""", """
1032I feel &lt;strong&gt;!
1033""")
1034
1035  /////////////////////////////////////////////////////////////////////
1036  //
1037  //  Unescaping HTML: `!=`
1038  //
1039  /////////////////////////////////////////////////////////////////////
1040
1041  testRender(
1042    "'!= expression' does not santize the rendered expression",
1043    """
1044!= "I feel <strong>!"
1045""", """
1046I feel <strong>!
1047""")
1048
1049  testRender(
1050    "'! text' does not santize interpolated expressions",
1051    """
1052! I feel #{"<strong>"}!
1053""", """
1054I feel <strong>!
1055""")
1056
1057  testRender(
1058    "'-@ val' makes an attribute accessibe as variable",
1059    """
1060-@ val bean:Bean
1061| The bean is #{bean.color}
1062""", """
1063The bean is red
1064""")
1065
1066  testRender(
1067    "'-@ import val' makes an attribute's members accessibe as variables",
1068    """
1069-@ import val bean:Bean
1070| The bean is #{color}
1071""", """
1072The bean is red
1073""")
1074
1075  testRender(
1076    "'-@ val name:type = expression' can specify a default value if the named attribute is not set",
1077    """
1078-@ val doesnotexist:Bean = Bean("blue", 5)
1079| The bean is #{doesnotexist.color}
1080""", """
1081The bean is blue
1082""")
1083
1084  testRender(
1085    "'-@ val' can be used in nested tags",
1086    """
1087html
1088  | test
1089  -@ val bean:Bean
1090  | The bean is #{bean.color}
1091""", """
1092<html>
1093  test
1094  The bean is red
1095</html>
1096""")
1097
1098  /////////////////////////////////////////////////////////////////////
1099  //
1100  // Preserving White Space
1101  //
1102  /////////////////////////////////////////////////////////////////////
1103  testRender(
1104    "Generated content in dynamic expression are properly indented.",
1105    """
1106html
1107  p
1108    = "line1\nline2\nline3"
1109""", """
1110<html>
1111  <p>
1112    line1
1113    line2
1114    line3
1115  </p>
1116</html>
1117""")
1118
1119  testRender(
1120    "`~` preserves white space",
1121    """
1122html
1123  p
1124    ~ "line1\nline2\nline3"
1125""", """
1126<html>
1127  <p>
1128    line1&#x000A;line2&#x000A;line3
1129  </p>
1130</html>
1131""")
1132
1133  testRender(
1134    "`&~` preserves and sanitizes",
1135    """
1136&~ "<tag>\n</tag>"
1137""", """
1138&lt;tag&gt;&#x000A;&lt;/tag&gt;
1139""")
1140
1141  testRender(
1142    "`!~` preserves and does not sanitize",
1143    """
1144!~ "<tag>\n</tag>"
1145""", """
1146<tag>&#x000A;</tag>
1147""")
1148
1149  testRender(
1150    "`~~` ugly preserves white space. values are not indented at all.",
1151    """
1152html
1153  p
1154    ~~ "line1\nline2\nline3"
1155""", """
1156<html>
1157  <p>
1158line1
1159line2
1160line3
1161  </p>
1162</html>
1163""")
1164
1165  testRender(
1166    "If the ScamlOptions.ugly option is enabled, then `=` behaves like `~~`",
1167    """
1168html
1169  p
1170    = "line1\nline2\nline3"
1171""", """
1172<html>
1173  <p>
1174line1
1175line2
1176line3
1177  </p>
1178</html>
1179""", { () =>
1180      ScamlOptions.ugly = true
1181    }, { () =>
1182      ScamlOptions.ugly = ScamlOptions.DEFAULT_UGLY
1183    })
1184
1185  /////////////////////////////////////////////////////////////////////
1186  //
1187  // Indent Handling..
1188  // You should enable white space viewing in your editor before touching this
1189  // section.
1190  //
1191  /////////////////////////////////////////////////////////////////////
1192  testRender(
1193    "Jade eats empty lines",
1194    """
1195ul
1196  li item 1
1197
1198  ul
1199    li item 1
1200
1201    li item 2
1202
1203  li item 2
1204
1205p test
1206""", """
1207<ul>
1208  <li>item 1</li>
1209  <ul>
1210    <li>item 1</li>
1211    <li>item 2</li>
1212  </ul>
1213  <li>item 2</li>
1214</ul>
1215<p>test</p>
1216""")
1217
1218  testRender(
1219    "Jade does not eat empty lines in a filter",
1220    """
1221:plain
1222  item 1
1223
1224  item 2
1225p test
1226""", """
1227item 1
1228
1229item 2
1230<p>test</p>
1231""")
1232
1233  // https://groups.google.com/group/scalate/browse_thread/thread/fb0816c388936541
1234  testRender(
1235    "Supports consecutive includes",
1236    """
1237- include("/jade-include-1.jade")
1238- include("/jade-include-2.jade")
1239""", """
1240<p>1</p>
1241<p>2</p>
1242""")
1243}
1244
1245case class Bean(color: String, size: Int) {
1246
1247  def link = {
1248    <a href={ "#size-" + size }>{ color }</a>
1249  }
1250
1251}