PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/gems/haml-2.0.3/test/haml/engine_test.rb

https://github.com/technicalpickles/flockup
Ruby | 565 lines | 466 code | 86 blank | 13 comment | 10 complexity | eb87719b66f55856f0e126fa82e15149 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/usr/bin/env ruby
  2. require File.dirname(__FILE__) + '/../test_helper'
  3. class EngineTest < Test::Unit::TestCase
  4. # A map of erroneous Haml documents to the error messages they should produce.
  5. # The error messages may be arrays;
  6. # if so, the second element should be the line number that should be reported for the error.
  7. # If this isn't provided, the tests will assume the line number should be the last line of the document.
  8. EXCEPTION_MAP = {
  9. "!!!\n a" => "Illegal nesting: nesting within a header command is illegal.",
  10. "a\n b" => "Illegal nesting: nesting within plain text is illegal.",
  11. "/ a\n b" => "Illegal nesting: nesting within a tag that already has content is illegal.",
  12. "% a" => 'Invalid tag: "% a".',
  13. "%p a\n b" => "Illegal nesting: content can't be both given on the same line as %p and nested within it.",
  14. "%p=" => "There's no Ruby code for = to evaluate.",
  15. "%p~" => "There's no Ruby code for ~ to evaluate.",
  16. "~" => "There's no Ruby code for ~ to evaluate.",
  17. "=" => "There's no Ruby code for = to evaluate.",
  18. "%p/\n a" => "Illegal nesting: nesting within a self-closing tag is illegal.",
  19. "%p\n\ta" => <<END.strip,
  20. A tab character was used for indentation. Haml must be indented using two spaces.
  21. Are you sure you have soft tabs enabled in your editor?
  22. END
  23. "%p\n a" => "1 space was used for indentation. Haml must be indented using two spaces.",
  24. "%p\n a" => "3 spaces were used for indentation. Haml must be indented using two spaces.",
  25. "%p\n a" => "4 spaces were used for indentation. Haml must be indented using two spaces.",
  26. ":a\n b" => ['Filter "a" is not defined.', 1],
  27. ":a= b" => 'Invalid filter name ":a= b".',
  28. "." => "Illegal element: classes and ids must have values.",
  29. ".#" => "Illegal element: classes and ids must have values.",
  30. ".{} a" => "Illegal element: classes and ids must have values.",
  31. ".= a" => "Illegal element: classes and ids must have values.",
  32. "%p..a" => "Illegal element: classes and ids must have values.",
  33. "%a/ b" => "Self-closing tags can't have content.",
  34. " %p foo" => "Indenting at the beginning of the document is illegal.",
  35. " %p foo" => "Indenting at the beginning of the document is illegal.",
  36. "- end" => "You don't need to use \"- end\" in Haml. Use indentation instead:\n- if foo?\n %strong Foo!\n- else\n Not foo.",
  37. " \n\t\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3],
  38. # Regression tests
  39. "- raise 'foo'\n\n\n\nbar" => ["foo", 1],
  40. "= 'foo'\n-raise 'foo'" => ["foo", 2],
  41. "\n\n\n- raise 'foo'" => ["foo", 4],
  42. "foo\n\n\n bar" => ["Illegal nesting: nesting within plain text is illegal.", 4],
  43. "%p/\n\n bar" => ["Illegal nesting: nesting within a self-closing tag is illegal.", 3],
  44. "%p foo\n\n bar" => ["Illegal nesting: content can't be both given on the same line as %p and nested within it.", 3],
  45. "/ foo\n\n bar" => ["Illegal nesting: nesting within a tag that already has content is illegal.", 3],
  46. "!!!\n\n bar" => ["Illegal nesting: nesting within a header command is illegal.", 3],
  47. "foo\n\n\n\tbar" => [<<END.strip, 4],
  48. A tab character was used for indentation. Haml must be indented using two spaces.
  49. Are you sure you have soft tabs enabled in your editor?
  50. END
  51. "foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
  52. }
  53. User = Struct.new('User', :id)
  54. def render(text, options = {}, &block)
  55. scope = options.delete(:scope) || Object.new
  56. locals = options.delete(:locals) || {}
  57. engine(text, options).to_html(scope, locals, &block)
  58. end
  59. def engine(text, options = {})
  60. unless options[:filename]
  61. # use caller method name as fake filename. useful for debugging
  62. i = -1
  63. caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0
  64. options[:filename] = "(#{$1})"
  65. end
  66. Haml::Engine.new(text, options)
  67. end
  68. def test_empty_render_should_remain_empty
  69. assert_equal('', render(''))
  70. end
  71. def test_attributes_should_render_correctly
  72. assert_equal("<div class='atlantis' style='ugly'></div>", render(".atlantis{:style => 'ugly'}").chomp)
  73. end
  74. def test_ruby_code_should_work_inside_attributes
  75. author = 'hcatlin'
  76. assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
  77. end
  78. def test_nil_should_render_empty_tag
  79. assert_equal("<div class='no_attributes'></div>",
  80. render(".no_attributes{:nil => nil}").chomp)
  81. end
  82. def test_strings_should_get_stripped_inside_tags
  83. assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
  84. render(".stripped This should have no spaces in front of it").chomp)
  85. end
  86. def test_one_liner_should_be_one_line
  87. assert_equal("<p>Hello</p>", render('%p Hello').chomp)
  88. end
  89. def test_one_liner_with_newline_shouldnt_be_one_line
  90. assert_equal("<p>\n foo\n bar\n</p>", render('%p= "foo\nbar"').chomp)
  91. end
  92. def test_multi_render
  93. engine = engine("%strong Hi there!")
  94. assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
  95. assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
  96. assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
  97. end
  98. def test_double_equals
  99. assert_equal("<p>Hello World</p>\n", render('%p== Hello #{who}', :locals => {:who => 'World'}))
  100. assert_equal("<p>\n Hello World\n</p>\n", render("%p\n == Hello \#{who}", :locals => {:who => 'World'}))
  101. end
  102. def test_double_equals_in_the_middle_of_a_string
  103. assert_equal("\"title 'Title'. \"\n",
  104. render("== \"title '\#{\"Title\"}'. \""))
  105. end
  106. def test_nil_tag_value_should_render_as_empty
  107. assert_equal("<p></p>\n", render("%p= nil"))
  108. end
  109. def test_tag_with_failed_if_should_render_as_empty
  110. assert_equal("<p></p>\n", render("%p= 'Hello' if false"))
  111. end
  112. def test_static_attributes_with_empty_attr
  113. assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:src => '/foo.png', :alt => ''}"))
  114. end
  115. def test_dynamic_attributes_with_empty_attr
  116. assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}"))
  117. end
  118. def test_end_of_file_multiline
  119. assert_equal("<p>0</p>\n<p>1</p>\n<p>2</p>\n", render("- for i in (0...3)\n %p= |\n i |"))
  120. end
  121. def test_cr_newline
  122. assert_equal("<p>foo</p>\n<p>bar</p>\n<p>baz</p>\n<p>boom</p>\n", render("%p foo\r%p bar\r\n%p baz\n\r%p boom"))
  123. end
  124. def test_textareas
  125. assert_equal("<textarea>Foo&#x000A; bar&#x000A; baz</textarea>\n",
  126. render('%textarea= "Foo\n bar\n baz"'))
  127. assert_equal("<pre>Foo&#x000A; bar&#x000A; baz</pre>\n",
  128. render('%pre= "Foo\n bar\n baz"'))
  129. assert_equal("<textarea>#{'a' * 100}</textarea>\n",
  130. render("%textarea #{'a' * 100}"))
  131. assert_equal("<p>\n <textarea>Foo\n Bar\n Baz</textarea>\n</p>\n", render(<<SOURCE))
  132. %p
  133. %textarea
  134. Foo
  135. Bar
  136. Baz
  137. SOURCE
  138. end
  139. def test_boolean_attributes
  140. assert_equal("<p bar baz='true' foo='bar'></p>\n",
  141. render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4))
  142. assert_equal("<p bar='bar' baz='true' foo='bar'></p>\n",
  143. render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml))
  144. assert_equal("<p baz='false' foo='bar'></p>\n",
  145. render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4))
  146. assert_equal("<p baz='false' foo='bar'></p>\n",
  147. render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml))
  148. end
  149. def test_both_whitespace_nukes_work_together
  150. assert_equal(<<RESULT, render(<<SOURCE))
  151. <p><q>Foo
  152. Bar</q></p>
  153. RESULT
  154. %p
  155. %q><= "Foo\\nBar"
  156. SOURCE
  157. end
  158. # HTML escaping tests
  159. def test_ampersand_equals_should_escape
  160. assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
  161. end
  162. def test_ampersand_equals_inline_should_escape
  163. assert_equal("<p>foo &amp; bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
  164. end
  165. def test_ampersand_equals_should_escape_before_preserve
  166. assert_equal("<textarea>foo&#x000A;bar</textarea>\n", render('%textarea&= "foo\nbar"', :escape_html => false))
  167. end
  168. def test_bang_equals_should_not_escape
  169. assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
  170. end
  171. def test_bang_equals_inline_should_not_escape
  172. assert_equal("<p>foo & bar</p>\n", render("%p!= 'foo & bar'", :escape_html => true))
  173. end
  174. def test_static_attributes_should_be_escaped
  175. assert_equal("<img class='atlantis' style='ugly&amp;stupid' />\n",
  176. render("%img.atlantis{:style => 'ugly&stupid'}"))
  177. assert_equal("<div class='atlantis' style='ugly&amp;stupid'>foo</div>\n",
  178. render(".atlantis{:style => 'ugly&stupid'} foo"))
  179. assert_equal("<p class='atlantis' style='ugly&amp;stupid'>foo</p>\n",
  180. render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'"))
  181. assert_equal("<p class='atlantis' style='ugly&#x000A;stupid'></p>\n",
  182. render("%p.atlantis{:style => \"ugly\\nstupid\"}"))
  183. end
  184. def test_dynamic_attributes_should_be_escaped
  185. assert_equal("<img alt='' src='&amp;foo.png' />\n",
  186. render("%img{:width => nil, :src => '&foo.png', :alt => String.new}"))
  187. assert_equal("<p alt='' src='&amp;foo.png'>foo</p>\n",
  188. render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo"))
  189. assert_equal("<div alt='' src='&amp;foo.png'>foo</div>\n",
  190. render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'"))
  191. assert_equal("<img alt='' src='foo&#x000A;.png' />\n",
  192. render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}"))
  193. end
  194. def test_string_interpolation_should_be_esaped
  195. assert_equal("<p>4&amp;3</p>\n", render("%p== #{2+2}&#{2+1}", :escape_html => true))
  196. assert_equal("<p>4&3</p>\n", render("%p== #{2+2}&#{2+1}", :escape_html => false))
  197. end
  198. def test_escaped_inline_string_interpolation
  199. assert_equal("<p>4&amp;3</p>\n", render("%p&== #{2+2}&#{2+1}", :escape_html => true))
  200. assert_equal("<p>4&amp;3</p>\n", render("%p&== #{2+2}&#{2+1}", :escape_html => false))
  201. end
  202. def test_unescaped_inline_string_interpolation
  203. assert_equal("<p>4&3</p>\n", render("%p!== #{2+2}&#{2+1}", :escape_html => true))
  204. assert_equal("<p>4&3</p>\n", render("%p!== #{2+2}&#{2+1}", :escape_html => false))
  205. end
  206. def test_escaped_string_interpolation
  207. assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n &== #{2+2}&#{2+1}", :escape_html => true))
  208. assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n &== #{2+2}&#{2+1}", :escape_html => false))
  209. end
  210. def test_unescaped_string_interpolation
  211. assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== #{2+2}&#{2+1}", :escape_html => true))
  212. assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== #{2+2}&#{2+1}", :escape_html => false))
  213. end
  214. def test_scripts_should_respect_escape_html_option
  215. assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
  216. assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
  217. end
  218. def test_inline_scripts_should_respect_escape_html_option
  219. assert_equal("<p>foo &amp; bar</p>\n", render("%p= 'foo & bar'", :escape_html => true))
  220. assert_equal("<p>foo & bar</p>\n", render("%p= 'foo & bar'", :escape_html => false))
  221. end
  222. def test_script_ending_in_comment_should_render_when_html_is_escaped
  223. assert_equal("foo&amp;bar\n", render("= 'foo&bar' #comment", :escape_html => true))
  224. end
  225. # Options tests
  226. def test_filename_and_line
  227. begin
  228. render("\n\n = abc", :filename => 'test', :line => 2)
  229. rescue Exception => e
  230. assert_kind_of Haml::SyntaxError, e
  231. assert_match(/test:4/, e.backtrace.first)
  232. end
  233. begin
  234. render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
  235. rescue Exception => e
  236. assert_kind_of NoMethodError, e
  237. assert_match(/test:6/, e.backtrace.first)
  238. end
  239. end
  240. def test_stop_eval
  241. assert_equal("", render("= 'Hello'", :suppress_eval => true))
  242. assert_equal("", render("- puts 'foo'", :suppress_eval => true))
  243. assert_equal("<div id='foo' yes='no' />\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
  244. assert_equal("<div id='foo' />\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
  245. assert_equal("<div />\n", render("%div[1]/", :suppress_eval => true))
  246. assert_equal("", render(":ruby\n puts 'hello'", :suppress_eval => true))
  247. end
  248. def test_attr_wrapper
  249. assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
  250. assert_equal("<p escaped='quo\"te'></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
  251. assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
  252. assert_equal("<p escaped=\"q'uo&quot;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
  253. assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
  254. end
  255. def test_attrs_parsed_correctly
  256. assert_equal("<p boom=>biddly='bar =&gt; baz'></p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
  257. assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
  258. assert_equal("<p escaped='quo&#x000A;te'></p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
  259. assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
  260. end
  261. def test_correct_parsing_with_brackets
  262. assert_equal("<p class='foo'>{tada} foo</p>\n", render("%p{:class => 'foo'} {tada} foo"))
  263. assert_equal("<p class='foo'>deep {nested { things }}</p>\n", render("%p{:class => 'foo'} deep {nested { things }}"))
  264. assert_equal("<p class='bar foo'>{a { d</p>\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d"))
  265. assert_equal("<p foo='bar'>a}</p>\n", render("%p{:foo => 'bar'} a}"))
  266. foo = []
  267. foo[0] = Struct.new('Foo', :id).new
  268. assert_equal("<p class='struct_foo' id='struct_foo_new'>New User]</p>\n",
  269. render("%p[foo[0]] New User]", :locals => {:foo => foo}))
  270. assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_new'>New User]</p>\n",
  271. render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
  272. foo[0].id = 1
  273. assert_equal("<p class='struct_foo' id='struct_foo_1'>New User]</p>\n",
  274. render("%p[foo[0]] New User]", :locals => {:foo => foo}))
  275. assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_1'>New User]</p>\n",
  276. render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
  277. end
  278. def test_empty_attrs
  279. assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => '' } empty"))
  280. assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => x } empty", :locals => {:x => ''}))
  281. end
  282. def test_nil_attrs
  283. assert_equal("<p>nil</p>\n", render("%p{ :attr => nil } nil"))
  284. assert_equal("<p>nil</p>\n", render("%p{ :attr => x } nil", :locals => {:x => nil}))
  285. end
  286. def test_nil_id_with_syntactic_id
  287. assert_equal("<p id='foo'>nil</p>\n", render("%p#foo{:id => nil} nil"))
  288. assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => 'bar'}, :id => nil} nil"))
  289. assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => nil}, :id => 'bar'} nil"))
  290. end
  291. def test_nil_class_with_syntactic_class
  292. assert_equal("<p class='foo'>nil</p>\n", render("%p.foo{:class => nil} nil"))
  293. assert_equal("<p class='bar foo'>nil</p>\n", render("%p.bar.foo{:class => nil} nil"))
  294. assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => 'bar'}, :class => nil} nil"))
  295. assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => nil}, :class => 'bar'} nil"))
  296. end
  297. def test_locals
  298. assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
  299. end
  300. def test_dynamic_attrs_shouldnt_register_as_literal_values
  301. assert_equal("<p a='b2c'></p>\n", render('%p{:a => "b#{1 + 1}c"}'))
  302. assert_equal("<p a='b2c'></p>\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}"))
  303. end
  304. def test_dynamic_attrs_with_self_closed_tag
  305. assert_equal("<a b='2' />\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n"))
  306. end
  307. def test_exceptions
  308. EXCEPTION_MAP.each do |key, value|
  309. begin
  310. render(key, :filename => "(exception test for #{key.inspect})")
  311. rescue Exception => err
  312. value = [value] unless value.is_a?(Array)
  313. expected_message, line_no = value
  314. line_no ||= key.split("\n").length
  315. line_reported = err.backtrace[0].gsub(/\(.+\):/, '').to_i
  316. assert_equal(expected_message, err.message, "Line: #{key}")
  317. assert_equal(line_no, line_reported, "Line: #{key}")
  318. else
  319. assert(false, "Exception not raised for\n#{key}")
  320. end
  321. end
  322. end
  323. def test_exception_line
  324. render("a\nb\n!!!\n c\nd")
  325. rescue Haml::SyntaxError => e
  326. assert_equal("(test_exception_line):4", e.backtrace[0])
  327. else
  328. assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
  329. end
  330. def test_exception
  331. render("%p\n hi\n %a= undefined\n= 12")
  332. rescue Exception => e
  333. assert_match("(test_exception):3", e.backtrace[0])
  334. else
  335. # Test failed... should have raised an exception
  336. assert(false)
  337. end
  338. def test_compile_error
  339. render("a\nb\n- fee)\nc")
  340. rescue Exception => e
  341. assert_match(/^compile error\n\(test_compile_error\):3: syntax error/i, e.message)
  342. else
  343. assert(false,
  344. '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
  345. end
  346. def test_unbalanced_brackets
  347. render('== #{1 + 5} foo #{6 + 7 bar #{8 + 9}')
  348. rescue Haml::SyntaxError => e
  349. assert_equal("Unbalanced brackets.", e.message)
  350. end
  351. def test_balanced_conditional_comments
  352. assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
  353. render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
  354. end
  355. def test_empty_filter
  356. assert_equal(<<END, render(':javascript'))
  357. <script type='text/javascript'>
  358. //<![CDATA[
  359. //]]>
  360. </script>
  361. END
  362. end
  363. def test_ugly_filter
  364. assert_equal(<<END, render(":sass\n #foo\n bar: baz", :ugly => true))
  365. #foo {
  366. bar: baz; }
  367. END
  368. end
  369. def test_local_assigns_dont_modify_class
  370. assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
  371. assert_equal(nil, defined?(foo))
  372. end
  373. def test_object_ref_with_nil_id
  374. user = User.new
  375. assert_equal("<p class='struct_user' id='struct_user_new'>New User</p>\n",
  376. render("%p[user] New User", :locals => {:user => user}))
  377. end
  378. def test_object_ref_before_attrs
  379. user = User.new 42
  380. assert_equal("<p class='struct_user' id='struct_user_42' style='width: 100px;'>New User</p>\n",
  381. render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user}))
  382. end
  383. def test_non_literal_attributes
  384. assert_equal("<p a1='foo' a2='bar' a3='baz' />\n",
  385. render("%p{a2, a1, :a3 => 'baz'}/",
  386. :locals => {:a1 => {:a1 => 'foo'}, :a2 => {:a2 => 'bar'}}))
  387. end
  388. def test_render_should_accept_a_binding_as_scope
  389. string = "This is a string!"
  390. string.instance_variable_set("@var", "Instance variable")
  391. b = string.instance_eval do
  392. var = "Local variable"
  393. binding
  394. end
  395. assert_equal("<p>THIS IS A STRING!</p>\n<p>Instance variable</p>\n<p>Local variable</p>\n",
  396. render("%p= upcase\n%p= @var\n%p= var", :scope => b))
  397. end
  398. def test_yield_should_work_with_binding
  399. assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 })
  400. end
  401. def test_yield_should_work_with_def_method
  402. s = "foo"
  403. engine("= yield\n= upcase").def_method(s, :render)
  404. assert_equal("12\nFOO\n", s.render { 12 })
  405. end
  406. def test_def_method_with_module
  407. engine("= yield\n= upcase").def_method(String, :render_haml)
  408. assert_equal("12\nFOO\n", "foo".render_haml { 12 })
  409. end
  410. def test_def_method_locals
  411. obj = Object.new
  412. engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
  413. assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", obj.render(:foo => 1, :baz => 2, :boom => 3))
  414. end
  415. def test_render_proc_locals
  416. proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
  417. assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", proc[:foo => 1, :baz => 2, :boom => 3])
  418. end
  419. def test_render_proc_with_binding
  420. assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call)
  421. end
  422. def test_ugly_true
  423. assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
  424. render("#outer\n #inner\n %p hello world", :ugly => true))
  425. assert_equal("<p>#{'s' * 75}</p>\n",
  426. render("%p #{'s' * 75}", :ugly => true))
  427. assert_equal("<p>#{'s' * 75}</p>\n",
  428. render("%p= 's' * 75", :ugly => true))
  429. end
  430. def test_auto_preserve_unless_ugly
  431. assert_equal("<pre>foo&#x000A;bar</pre>\n", render('%pre="foo\nbar"'))
  432. assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar"))
  433. assert_equal("<pre>foo\nbar</pre>\n", render('%pre="foo\nbar"', :ugly => true))
  434. assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar", :ugly => true))
  435. end
  436. def test_xhtml_output_option
  437. assert_equal "<p>\n <br />\n</p>\n", render("%p\n %br", :format => :xhtml)
  438. assert_equal "<a />\n", render("%a/", :format => :xhtml)
  439. end
  440. def test_arbitrary_output_option
  441. assert_raise(Haml::Error, "Invalid output format :html1") { engine("%br", :format => :html1) }
  442. end
  443. # HTML 4.0
  444. def test_html_has_no_self_closing_tags
  445. assert_equal "<p>\n <br>\n</p>\n", render("%p\n %br", :format => :html4)
  446. assert_equal "<br>\n", render("%br/", :format => :html4)
  447. end
  448. def test_html_renders_empty_node_with_closing_tag
  449. assert_equal "<div class='foo'></div>\n", render(".foo", :format => :html4)
  450. end
  451. def test_html_ignores_explicit_self_closing_declaration
  452. assert_equal "<a></a>\n", render("%a/", :format => :html4)
  453. end
  454. def test_html_ignores_xml_prolog_declaration
  455. assert_equal "", render('!!! XML', :format => :html4)
  456. end
  457. def test_html_has_different_doctype
  458. assert_equal %{<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n},
  459. render('!!!', :format => :html4)
  460. end
  461. # because anything before the doctype triggers quirks mode in IE
  462. def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
  463. assert_no_match(/^\s+/, render("!!! xml\n!!!", :format => :html4))
  464. end
  465. # HTML5
  466. def test_html5_doctype
  467. assert_equal %{<!DOCTYPE html>\n}, render('!!!', :format => :html5)
  468. end
  469. end