haml 5.0.1 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2131 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'test_helper'
3
-
4
- class EngineTest < Haml::TestCase
5
- # A map of erroneous Haml documents to the error messages they should produce.
6
- # The error messages may be arrays;
7
- # if so, the second element should be the line number that should be reported for the error.
8
- # If this isn't provided, the tests will assume the line number should be the last line of the document.
9
- EXCEPTION_MAP = {
10
- "!!!\n a" => error(:illegal_nesting_header),
11
- "a\n b" => error(:illegal_nesting_plain),
12
- "/ a\n b" => error(:illegal_nesting_content),
13
- "% a" => error(:invalid_tag, '% a'),
14
- "%p a\n b" => error(:illegal_nesting_line, 'p'),
15
- "%p=" => error(:no_ruby_code, '='),
16
- "%p~" => error(:no_ruby_code, '~'),
17
- "~" => error(:no_ruby_code, '~'),
18
- "=" => error(:no_ruby_code, '='),
19
- "%p/\n a" => error(:illegal_nesting_self_closing),
20
- ":a\n b" => [error(:filter_not_defined, 'a'), 1],
21
- ":a= b" => error(:invalid_filter_name, 'a= b'),
22
- "." => error(:illegal_element),
23
- ".#" => error(:illegal_element),
24
- ".{} a" => error(:illegal_element),
25
- ".() a" => error(:illegal_element),
26
- ".= a" => error(:illegal_element),
27
- "%p..a" => error(:illegal_element),
28
- "%a/ b" => error(:self_closing_content),
29
- " %p foo" => error(:indenting_at_start),
30
- " %p foo" => error(:indenting_at_start),
31
- "- end" => error(:no_end),
32
- "%p{:a => 'b',\n:c => 'd'}/ e" => [error(:self_closing_content), 2],
33
- "%p{:a => 'b',\n:c => 'd'}=" => [error(:no_ruby_code, '='), 2],
34
- "%p.{:a => 'b',\n:c => 'd'} e" => [error(:illegal_element), 1],
35
- "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n%p/ a" => [error(:self_closing_content), 4],
36
- "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n- raise 'foo'" => ["foo", 4],
37
- "%p{:a => 'b',\n:c => raise('foo'),\n:e => 'f'}" => ["foo", 2],
38
- "%p{:a => 'b',\n:c => 'd',\n:e => raise('foo')}" => ["foo", 3],
39
- " \n\t\n %p foo" => [error(:indenting_at_start), 3],
40
- "\n\n %p foo" => [error(:indenting_at_start), 3],
41
- "%p\n foo\n foo" => [error(:inconsistent_indentation, "1 space", "2 spaces"), 3],
42
- "%p\n foo\n%p\n foo" => [error(:inconsistent_indentation, "1 space", "2 spaces"), 4],
43
- "%p\n\t\tfoo\n\tfoo" => [error(:inconsistent_indentation, "1 tab", "2 tabs"), 3],
44
- "%p\n foo\n foo" => [error(:inconsistent_indentation, "3 spaces", "2 spaces"), 3],
45
- "%p\n foo\n %p\n bar" => [error(:inconsistent_indentation, "3 spaces", "2 spaces"), 4],
46
- "%p\n :plain\n bar\n \t baz" => [error(:inconsistent_indentation, '" \t "', "2 spaces"), 4],
47
- "%p\n foo\n%p\n bar" => [error(:deeper_indenting, 2), 4],
48
- "%p\n foo\n %p\n bar" => [error(:deeper_indenting, 3), 4],
49
- "%p\n \tfoo" => [error(:cant_use_tabs_and_spaces), 2],
50
- "%p(" => error(:invalid_attribute_list, '"("'),
51
- "%p(foo=)" => error(:invalid_attribute_list, '"(foo=)"'),
52
- "%p(foo 'bar')" => error(:invalid_attribute_list, '"(foo \'bar\')"'),
53
- "%p(foo=\nbar)" => [error(:invalid_attribute_list, '"(foo="'), 1],
54
- "%p(foo 'bar'\nbaz='bang')" => [error(:invalid_attribute_list, '"(foo \'bar\'"'), 1],
55
- "%p(foo='bar'\nbaz 'bang'\nbip='bop')" => [error(:invalid_attribute_list, '"(foo=\'bar\' baz \'bang\'"'), 2],
56
- "%p{'foo' => 'bar' 'bar' => 'baz'}" => :compile,
57
- "%p{:foo => }" => :compile,
58
- "%p{=> 'bar'}" => :compile,
59
- "%p{'foo => 'bar'}" => :compile,
60
- "%p{:foo => 'bar}" => :compile,
61
- "%p{:foo => 'bar\"}" => :compile,
62
- # Regression tests
63
- "foo\n\n\n bar" => [error(:illegal_nesting_plain), 4],
64
- "%p/\n\n bar" => [error(:illegal_nesting_self_closing), 3],
65
- "%p foo\n\n bar" => [error(:illegal_nesting_line, 'p'), 3],
66
- "/ foo\n\n bar" => [error(:illegal_nesting_content), 3],
67
- "!!!\n\n bar" => [error(:illegal_nesting_header), 3],
68
- "- raise 'foo'\n\n\n\nbar" => ["foo", 1],
69
- "= 'foo'\n-raise 'foo'" => ["foo", 2],
70
- "\n\n\n- raise 'foo'" => ["foo", 4],
71
- "%p foo |\n bar |\n baz |\nbop\n- raise 'foo'" => ["foo", 5],
72
- "foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
73
- "foo\n:erb\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
74
- "foo\n:plain\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
75
- "foo\n:plain\n 1\n 2\n 3\n4\n- raise 'foo'" => ["foo", 7],
76
- "foo\n:plain\n 1\n 2\n 3\#{''}\n- raise 'foo'" => ["foo", 6],
77
- "foo\n:plain\n 1\n 2\n 3\#{''}\n4\n- raise 'foo'" => ["foo", 7],
78
- "foo\n:plain\n 1\n 2\n \#{raise 'foo'}" => ["foo", 5],
79
- "= raise 'foo'\nfoo\nbar\nbaz\nbang" => ["foo", 1],
80
- "- case 1\n\n- when 1\n - raise 'foo'" => ["foo", 4],
81
- }
82
-
83
- User = Struct.new('User', :id)
84
- class CustomHamlClass < Struct.new(:id)
85
- def haml_object_ref
86
- "my_thing"
87
- end
88
- end
89
- CpkRecord = Struct.new('CpkRecord', :id) do
90
- def to_key
91
- [*self.id] unless id.nil?
92
- end
93
- end
94
-
95
- def use_test_tracing(options)
96
- unless options[:filename]
97
- # use caller method name as fake filename. useful for debugging
98
- i = -1
99
- caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0
100
- options[:filename] = "(#{$1})"
101
- end
102
- options
103
- end
104
-
105
- def render(text, options = {}, &block)
106
- options = use_test_tracing(options)
107
- super
108
- end
109
-
110
- def engine(text, options = {})
111
- options = use_test_tracing(options)
112
- Haml::Engine.new(text, options)
113
- end
114
-
115
- def setup
116
- @old_default_internal = Encoding.default_internal
117
- silence_warnings{Encoding.default_internal = nil}
118
- end
119
-
120
- def teardown
121
- silence_warnings{Encoding.default_internal = @old_default_internal}
122
- end
123
-
124
- def test_empty_render
125
- assert_equal "", render("")
126
- end
127
-
128
- def test_flexible_tabulation
129
- assert_equal("<p>\nfoo\n</p>\n<q>\nbar\n<a>\nbaz\n</a>\n</q>\n",
130
- render("%p\n foo\n%q\n bar\n %a\n baz"))
131
- assert_equal("<p>\nfoo\n</p>\n<q>\nbar\n<a>\nbaz\n</a>\n</q>\n",
132
- render("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz"))
133
- assert_equal("<p>\n \t \t bar\n baz\n</p>\n",
134
- render("%p\n :plain\n \t \t bar\n baz"))
135
- end
136
-
137
- def test_empty_render_should_remain_empty
138
- assert_equal('', render(''))
139
- end
140
-
141
- def test_attributes_should_render_correctly
142
- assert_equal("<div class='atlantis' style='ugly'></div>", render(".atlantis{:style => 'ugly'}").chomp)
143
- end
144
-
145
- def test_css_id_as_attribute_should_be_appended_with_underscore
146
- assert_equal("<div id='my_id_1'></div>", render("#my_id{:id => '1'}").chomp)
147
- assert_equal("<div id='my_id_1'></div>", render("#my_id{:id => 1}").chomp)
148
- end
149
-
150
- def test_ruby_code_should_work_inside_attributes
151
- assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
152
- end
153
-
154
- def test_attributes_with_interpolation
155
- assert_equal("<iframe id='test' src='http://www.google.com/abc/'></iframe>\n", render(<<-'HAML'))
156
- - base_url = "http://www.google.com"
157
- %iframe#test{src: "#{File.join base_url, '/abc/'}"}
158
- HAML
159
- end
160
-
161
- def test_class_attr_with_array
162
- assert_equal("<p class='a b'>foo</p>\n", render("%p{:class => %w[a b]} foo")) # basic
163
- assert_equal("<p class='a b css'>foo</p>\n", render("%p.css{:class => %w[a b]} foo")) # merge with css
164
- assert_equal("<p class='b css'>foo</p>\n", render("%p.css{:class => %w[css b]} foo")) # merge uniquely
165
- assert_equal("<p class='a b c d'>foo</p>\n", render("%p{:class => [%w[a b], %w[c d]]} foo")) # flatten
166
- assert_equal("<p class='a b'>foo</p>\n", render("%p{:class => [:a, :b] } foo")) # stringify
167
- assert_equal("<p>foo</p>\n", render("%p{:class => [nil, false] } foo")) # strip falsey
168
- assert_equal("<p class='a'>foo</p>\n", render("%p{:class => :a} foo")) # single stringify
169
- assert_equal("<p>foo</p>\n", render("%p{:class => false} foo")) # single falsey
170
- assert_equal("<p class='a b html'>foo</p>\n", render("%p(class='html'){:class => %w[a b]} foo")) # html attrs
171
- end
172
-
173
- def test_id_attr_with_array
174
- assert_equal("<p id='a_b'>foo</p>\n", render("%p{:id => %w[a b]} foo")) # basic
175
- assert_equal("<p id='css_a_b'>foo</p>\n", render("%p#css{:id => %w[a b]} foo")) # merge with css
176
- assert_equal("<p id='a_b_c_d'>foo</p>\n", render("%p{:id => [%w[a b], %w[c d]]} foo")) # flatten
177
- assert_equal("<p id='a_b'>foo</p>\n", render("%p{:id => [:a, :b] } foo")) # stringify
178
- assert_equal("<p>foo</p>\n", render("%p{:id => [nil, false] } foo")) # strip falsey
179
- assert_equal("<p id='a'>foo</p>\n", render("%p{:id => :a} foo")) # single stringify
180
- assert_equal("<p>foo</p>\n", render("%p{:id => false} foo")) # single falsey
181
- assert_equal("<p id='html_a_b'>foo</p>\n", render("%p(id='html'){:id => %w[a b]} foo")) # html attrs
182
- end
183
-
184
- def test_colon_in_class_attr
185
- assert_equal("<p class='foo:bar'>\n", render("%p.foo:bar/"))
186
- end
187
-
188
- def test_colon_in_id_attr
189
- assert_equal("<p id='foo:bar'>\n", render("%p#foo:bar/"))
190
- end
191
-
192
- def test_dynamic_attributes_with_no_content
193
- assert_equal(<<HTML, render(<<HAML))
194
- <p>
195
- <a href='http://haml.info'></a>
196
- </p>
197
- HTML
198
- %p
199
- %a{:href => "http://" + "haml.info"}
200
- HAML
201
- end
202
-
203
- def test_attributes_with_to_s
204
- assert_equal(<<HTML, render(<<HAML))
205
- <p id='foo_2'></p>
206
- <p class='2 foo'></p>
207
- <p blaz='2'></p>
208
- <p 2='2'></p>
209
- HTML
210
- %p#foo{:id => 1+1}
211
- %p.foo{:class => 1+1}
212
- %p{:blaz => 1+1}
213
- %p{(1+1) => 1+1}
214
- HAML
215
- end
216
-
217
- def test_nil_should_render_empty_tag
218
- assert_equal("<div class='no_attributes'></div>",
219
- render(".no_attributes{:nil => nil}").chomp)
220
- end
221
-
222
- def test_strings_should_get_stripped_inside_tags
223
- assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
224
- render(".stripped This should have no spaces in front of it").chomp)
225
- end
226
-
227
- def test_one_liner_should_be_one_line
228
- assert_equal("<p>Hello</p>", render('%p Hello').chomp)
229
- end
230
-
231
- def test_one_liner_with_newline_shouldnt_be_one_line
232
- assert_equal("<p>foo\nbar</p>", render('%p= "foo\nbar"').chomp)
233
- end
234
-
235
- def test_multi_render
236
- engine = engine("%strong Hi there!")
237
- assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
238
- assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
239
- assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
240
- end
241
-
242
- def test_interpolation
243
- assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', locals: {who: 'World'}, escape_html: false))
244
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: false))
245
- assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', locals: {who: 'World'}, escape_html: true))
246
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: true))
247
- end
248
-
249
- def test_interpolation_with_instance_var
250
- scope = Object.new
251
- scope.instance_variable_set(:@who, 'World')
252
-
253
- assert_equal("<p>Hello World</p>\n", render('%p Hello #@who', scope: scope, escape_html: false))
254
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#@who", scope: scope, escape_html: false))
255
- assert_equal("<p>Hello World</p>\n", render('%p Hello #@who', scope: scope, escape_html: true))
256
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#@who", scope: scope, escape_html: true))
257
- end
258
-
259
- def test_interpolation_with_global
260
- $global_var_for_testing = 'World'
261
-
262
- assert_equal("<p>Hello World</p>\n", render('%p Hello #$global_var_for_testing', escape_html: false))
263
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#$global_var_for_testing", escape_html: false))
264
- assert_equal("<p>Hello World</p>\n", render('%p Hello #$global_var_for_testing', escape_html: true))
265
- assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#$global_var_for_testing", escape_html: true))
266
- ensure
267
- $global_var_for_testing = nil
268
- end
269
-
270
- def test_interpolation_in_the_middle_of_a_string
271
- assert_equal("\"title 'Title'. \"\n",
272
- render("\"title '\#{\"Title\"}'. \""))
273
- end
274
-
275
- def test_interpolation_with_instance_var_in_the_middle_of_a_string
276
- scope = Object.new
277
- scope.instance_variable_set(:@title, 'Title')
278
-
279
- assert_equal("\"title 'Title'. \"\n",
280
- render("\"title '\#@title'. \"", :scope => scope))
281
- end
282
-
283
- def test_interpolation_with_global_in_the_middle_of_a_string
284
- $global_var_for_testing = 'Title'
285
-
286
- assert_equal("\"title 'Title'. \"\n",
287
- render("\"title '\#$global_var_for_testing'. \""))
288
- ensure
289
- $global_var_for_testing = nil
290
- end
291
-
292
- def test_interpolation_at_the_beginning_of_a_line
293
- assert_equal("<p>2</p>\n", render('%p #{1 + 1}'))
294
- assert_equal("<p>\n2\n</p>\n", render("%p\n \#{1 + 1}"))
295
- end
296
-
297
- def test_interpolation_with_instance_var_at_the_beginning_of_a_line
298
- scope = Object.new
299
- scope.instance_variable_set(:@foo, 2)
300
-
301
- assert_equal("<p>2</p>\n", render('%p #@foo', :scope => scope))
302
- assert_equal("<p>\n2\n</p>\n", render("%p\n \#@foo", :scope => scope))
303
- end
304
-
305
- def test_interpolation_with_global_at_the_beginning_of_a_line
306
- $global_var_for_testing = 2
307
-
308
- assert_equal("<p>2</p>\n", render('%p #$global_var_for_testing'))
309
- assert_equal("<p>\n2\n</p>\n", render("%p\n \#$global_var_for_testing"))
310
- ensure
311
- $global_var_for_testing = nil
312
- end
313
-
314
- def test_escaped_interpolation
315
- assert_equal("<p>Foo &amp; Bar & Baz</p>\n", render('%p& Foo #{"&"} Bar & Baz'))
316
- end
317
-
318
- def test_nil_tag_value_should_render_as_empty
319
- assert_equal("<p></p>\n", render("%p= nil"))
320
- end
321
-
322
- def test_tag_with_failed_if_should_render_as_empty
323
- assert_equal("<p></p>\n", render("%p= 'Hello' if false"))
324
- end
325
-
326
- def test_static_attributes_with_empty_attr
327
- assert_equal("<img alt='' src='/foo.png'>\n", render("%img{:src => '/foo.png', :alt => ''}"))
328
- end
329
-
330
- def test_dynamic_attributes_with_empty_attr
331
- assert_equal("<img alt='' src='/foo.png'>\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}"))
332
- end
333
-
334
- def test_attribute_hash_with_newlines
335
- assert_equal("<p a='b' c='d'>foop</p>\n", render("%p{:a => 'b',\n :c => 'd'} foop"))
336
- assert_equal("<p a='b' c='d'>\nfoop\n</p>\n", render("%p{:a => 'b',\n :c => 'd'}\n foop"))
337
- assert_equal("<p a='b' c='d'>\n", render("%p{:a => 'b',\n :c => 'd'}/"))
338
- assert_equal("<p a='b' c='d' e='f'></p>\n", render("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}"))
339
- end
340
-
341
- def test_attr_hashes_not_modified
342
- hash = {:color => 'red'}
343
- assert_equal(<<HTML, render(<<HAML, :locals => {:hash => hash}))
344
- <div color='red'></div>
345
- <div class='special' color='red'></div>
346
- <div color='red'></div>
347
- HTML
348
- %div{hash}
349
- .special{hash}
350
- %div{hash}
351
- HAML
352
- assert_equal(hash, {:color => 'red'})
353
- end
354
-
355
- def test_semi_prerendered_tags
356
- assert_equal(<<HTML, render(<<HAML))
357
- <p a='2'></p>
358
- <p a='2'>foo</p>
359
- <p a='2'>
360
- <p a='2'>foo</p>
361
- <p a='2'>foo
362
- bar</p>
363
- <p a='2'>foo
364
- bar</p>
365
- <p a='2'>
366
- foo
367
- </p>
368
- HTML
369
- %p{:a => 1 + 1}
370
- %p{:a => 1 + 1} foo
371
- %p{:a => 1 + 1}/
372
- %p{:a => 1 + 1}= "foo"
373
- %p{:a => 1 + 1}= "foo\\nbar"
374
- %p{:a => 1 + 1}~ "foo\\nbar"
375
- %p{:a => 1 + 1}
376
- foo
377
- HAML
378
- end
379
-
380
- def test_end_of_file_multiline
381
- assert_equal("<p>0</p>\n<p>1</p>\n<p>2</p>\n", render("- for i in (0...3)\n %p= |\n i |"))
382
- end
383
-
384
- def test_cr_newline
385
- 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"))
386
- end
387
-
388
- def test_textareas
389
- assert_equal("<textarea>Foo&#x000A; bar&#x000A; baz</textarea>\n",
390
- render('%textarea= "Foo\n bar\n baz"'))
391
-
392
- assert_equal("<pre>Foo&#x000A; bar&#x000A; baz</pre>\n",
393
- render('%pre= "Foo\n bar\n baz"'))
394
-
395
- assert_equal("<textarea>#{'a' * 100}</textarea>\n",
396
- render("%textarea #{'a' * 100}"))
397
-
398
- assert_equal("<p>\n<textarea>Foo\nBar\nBaz</textarea>\n</p>\n", render(<<SOURCE))
399
- %p
400
- %textarea
401
- Foo
402
- Bar
403
- Baz
404
- SOURCE
405
- end
406
-
407
- def test_pre_code
408
- assert_equal(<<HTML, render(<<HAML))
409
- <pre><code>Foo&#x000A; bar&#x000A; baz</code></pre>
410
- HTML
411
- %pre
412
- %code
413
- :preserve
414
- Foo
415
- bar
416
- baz
417
- HAML
418
- end
419
-
420
- def test_boolean_attributes
421
- assert_equal("<p bar baz='true' foo='bar'></p>\n",
422
- render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4))
423
- assert_equal("<p bar='bar' baz='true' foo='bar'></p>\n",
424
- render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml))
425
-
426
- assert_equal("<p baz='false' foo='bar'></p>\n",
427
- render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4))
428
- assert_equal("<p baz='false' foo='bar'></p>\n",
429
- render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml))
430
- end
431
-
432
- def test_nuke_inner_whitespace_in_loops
433
- assert_equal(<<HTML, render(<<HAML))
434
- <ul>foobarbaz</ul>
435
- HTML
436
- %ul<
437
- - for str in %w[foo bar baz]
438
- = str
439
- HAML
440
- end
441
-
442
- def test_both_whitespace_nukes_work_together
443
- assert_equal(<<RESULT, render(<<SOURCE))
444
- <p><q>Foo
445
- Bar</q></p>
446
- RESULT
447
- %p
448
- %q><= "Foo\\nBar"
449
- SOURCE
450
- end
451
-
452
- def test_nil_option
453
- assert_equal("<p foo='bar'></p>\n", render('%p{:foo => "bar"}', :attr_wrapper => nil))
454
- assert_equal("<p foo='bar'></p>\n", render('%p{foo: "bar"}', :attr_wrapper => nil))
455
- end
456
-
457
- def test_comment_with_crazy_nesting
458
- assert_equal(<<HTML, render(<<HAML))
459
- foo
460
- bar
461
- HTML
462
- foo
463
- -#
464
- ul
465
- %li{
466
- foo
467
- bar
468
- HAML
469
- end
470
-
471
- # Regression tests
472
-
473
- def test_indentation_after_dynamic_attr_hash
474
- assert_equal(<<HTML, render(<<HAML))
475
- <html>
476
- <body>
477
- <img src='test'>
478
- foo
479
- bar
480
- </body>
481
- </html>
482
- HTML
483
- %html
484
- %body
485
- %img{:src => 'te'+'st'}
486
- = "foo\\nbar"
487
- HAML
488
- end
489
-
490
- def test_whitespace_nuke_with_both_newlines
491
- assert_equal("<p>\nfoo\n</p>\n", render('%p<= "\nfoo\n"'))
492
- assert_equal(<<HTML, render(<<HAML))
493
- <p>
494
- <p>
495
- foo
496
- </p>
497
- </p>
498
- HTML
499
- %p
500
- %p<= "\\nfoo\\n"
501
- HAML
502
- end
503
-
504
- def test_whitespace_nuke_with_tags_and_else
505
- assert_equal(<<HTML, render(<<HAML))
506
- <a>
507
- <b>foo</b>
508
- </a>
509
- HTML
510
- %a
511
- %b<
512
- - if false
513
- = "foo"
514
- - else
515
- foo
516
- HAML
517
-
518
- assert_equal(<<HTML, render(<<HAML))
519
- <a>
520
- <b>
521
- foo
522
- </b>
523
- </a>
524
- HTML
525
- %a
526
- %b
527
- - if false
528
- = "foo"
529
- - else
530
- foo
531
- HAML
532
- end
533
-
534
- def test_outer_whitespace_nuke_with_empty_script
535
- assert_equal(<<HTML, render(<<HAML))
536
- <p>
537
- foo <a></a></p>
538
- HTML
539
- %p
540
- foo
541
- = " "
542
- %a>
543
- HAML
544
- end
545
-
546
- def test_both_case_indentation_work_with_deeply_nested_code
547
- result = <<RESULT
548
- <h2>
549
- other
550
- </h2>
551
- RESULT
552
- assert_equal(result, render(<<HAML))
553
- - case 'other'
554
- - when 'test'
555
- %h2
556
- hi
557
- - when 'other'
558
- %h2
559
- other
560
- HAML
561
- assert_equal(result, render(<<HAML))
562
- - case 'other'
563
- - when 'test'
564
- %h2
565
- hi
566
- - when 'other'
567
- %h2
568
- other
569
- HAML
570
- end
571
-
572
- def test_equals_block
573
- assert_equal("foo\n", render(<<HAML))
574
- = capture_haml do
575
- foo
576
- HAML
577
- end
578
-
579
- def test_plain_equals
580
- assert_equal("foo\nbar\n", render(<<HAML))
581
- = "foo"
582
- bar
583
- HAML
584
- end
585
-
586
- def test_inline_if
587
- assert_equal(<<HTML, render(<<HAML))
588
- <p>One</p>
589
- <p></p>
590
- <p>Three</p>
591
- HTML
592
- - for name in ["One", "Two", "Three"]
593
- %p= name unless name == "Two"
594
- HAML
595
- end
596
-
597
- def test_end_with_method_call
598
- assert_equal("2|3|4b-a-r", render(<<HAML))
599
- = [1, 2, 3].map do |i|
600
- - i + 1
601
- - end.join("|")
602
- = "bar".gsub(/./) do |s|
603
- - s + "-"
604
- - end.gsub(/-$/) do |s|
605
- - ''
606
- HAML
607
- end
608
-
609
- def test_nested_end_with_method_call
610
- assert_equal(<<HTML, render(<<HAML))
611
- <p>
612
- 2|3|4b-a-r</p>
613
- HTML
614
- %p
615
- = [1, 2, 3].map do |i|
616
- - i + 1
617
- - end.join("|")
618
- = "bar".gsub(/./) do |s|
619
- - s + "-"
620
- - end.gsub(/-$/) do |s|
621
- - ''
622
- HAML
623
- end
624
-
625
- def test_silent_end_with_stuff
626
- assert_equal(<<HTML, render(<<HAML))
627
- e
628
- d
629
- c
630
- b
631
- a
632
- HTML
633
- - str = "abcde"
634
- - if true
635
- = str.slice!(-1).chr
636
- - end until str.empty?
637
- HAML
638
-
639
- assert_equal(<<HTML, render(<<HAML))
640
- <p>hi!</p>
641
- HTML
642
- - if true
643
- %p hi!
644
- - end if "foo".gsub(/f/) do
645
- - "z"
646
- - end + "bar"
647
- HAML
648
- end
649
-
650
- def test_multiline_with_colon_after_filter
651
- assert_equal(<<HTML, render(<<HAML))
652
- Foo
653
- Bar
654
- HTML
655
- :plain
656
- Foo
657
- = { :a => "Bar", |
658
- :b => "Baz" }[:a] |
659
- HAML
660
- assert_equal(<<HTML, render(<<HAML))
661
-
662
- Bar
663
- HTML
664
- :plain
665
- = { :a => "Bar", |
666
- :b => "Baz" }[:a] |
667
- HAML
668
- end
669
-
670
- def test_multiline_in_filter
671
- assert_equal(<<HTML, render(<<HAML))
672
- Foo |
673
- Bar |
674
- Baz
675
- HTML
676
- :plain
677
- Foo |
678
- Bar |
679
- Baz
680
- HAML
681
- end
682
-
683
- def test_curly_brace
684
- assert_equal(<<HTML, render(<<HAML))
685
- Foo { Bar
686
- HTML
687
- == Foo { Bar
688
- HAML
689
- end
690
-
691
- def test_escape_attrs_false
692
- assert_equal(<<HTML, render(<<HAML, :escape_attrs => false))
693
- <div class='<?php echo "&quot;" ?>' id='foo'>
694
- bar
695
- </div>
696
- HTML
697
- #foo{:class => '<?php echo "&quot;" ?>'}
698
- bar
699
- HAML
700
- end
701
-
702
- def test_escape_attrs_always
703
- assert_equal(<<HTML, render(<<HAML, :escape_attrs => true))
704
- <div class='&quot;&amp;lt;&amp;gt;&amp;amp;&quot;' id='foo'>
705
- bar
706
- </div>
707
- HTML
708
- #foo{:class => '"&lt;&gt;&amp;"'}
709
- bar
710
- HAML
711
- end
712
-
713
- def test_escape_html
714
- html = <<HTML
715
- &amp;
716
- &
717
- &amp;
718
- HTML
719
-
720
- assert_equal(html, render(<<HAML, :escape_html => true))
721
- &= "&"
722
- != "&"
723
- = "&"
724
- HAML
725
-
726
- assert_equal(html, render(<<HAML, :escape_html => true))
727
- &~ "&"
728
- !~ "&"
729
- ~ "&"
730
- HAML
731
-
732
- assert_equal(html, render(<<HAML, :escape_html => true))
733
- & \#{"&"}
734
- ! \#{"&"}
735
- \#{"&"}
736
- HAML
737
-
738
- assert_equal(html, render(<<HAML, :escape_html => true))
739
- &== \#{"&"}
740
- !== \#{"&"}
741
- == \#{"&"}
742
- HAML
743
-
744
- tag_html = <<HTML
745
- <p>&amp;</p>
746
- <p>&</p>
747
- <p>&amp;</p>
748
- HTML
749
-
750
- assert_equal(tag_html, render(<<HAML, :escape_html => true))
751
- %p&= "&"
752
- %p!= "&"
753
- %p= "&"
754
- HAML
755
-
756
- assert_equal(tag_html, render(<<HAML, :escape_html => true))
757
- %p&~ "&"
758
- %p!~ "&"
759
- %p~ "&"
760
- HAML
761
-
762
- assert_equal(tag_html, render(<<HAML, :escape_html => true))
763
- %p& \#{"&"}
764
- %p! \#{"&"}
765
- %p \#{"&"}
766
- HAML
767
-
768
- assert_equal(tag_html, render(<<HAML, :escape_html => true))
769
- %p&== \#{"&"}
770
- %p!== \#{"&"}
771
- %p== \#{"&"}
772
- HAML
773
- end
774
-
775
- def test_new_attrs_with_hash
776
- assert_equal("<a href='#'></a>\n", render('%a(href="#")'))
777
- end
778
-
779
- def test_silent_script_with_hyphen_case
780
- assert_equal("", render("- a = 'foo-case-bar-case'"))
781
- end
782
-
783
- def test_silent_script_with_hyphen_end
784
- assert_equal("", render("- a = 'foo-end-bar-end'"))
785
- end
786
-
787
- def test_silent_script_with_hyphen_end_and_block
788
- silence_warnings do
789
- assert_equal(<<HTML, render(<<HAML))
790
- <p>foo-end</p>
791
- <p>bar-end</p>
792
- HTML
793
- - ("foo-end-bar-end".gsub(/\\w+-end/) do |s|
794
- %p= s
795
- - end; nil)
796
- HAML
797
- end
798
- end
799
-
800
- def test_if_without_content_and_else
801
- assert_equal(<<HTML, render(<<HAML))
802
- foo
803
- HTML
804
- - if false
805
- - else
806
- foo
807
- HAML
808
-
809
- assert_equal(<<HTML, render(<<HAML))
810
- foo
811
- HTML
812
- - if true
813
- - if false
814
- - else
815
- foo
816
- HAML
817
- end
818
-
819
- def test_html_attributes_with_hash
820
- assert_equal("<a href='#' rel='top'>Foo</a>\n",
821
- render('%a(href="#" rel="top") Foo'))
822
- assert_equal("<a href='#'>Foo</a>\n",
823
- render('%a(href="#") #{"Foo"}'))
824
-
825
- assert_equal("<a href='#&quot;'></a>\n", render('%a(href="#\\"")'))
826
- end
827
-
828
- def test_case_assigned_to_var
829
- assert_equal(<<HTML, render(<<HAML))
830
- bar
831
- HTML
832
- - var = case 12
833
- - when 1; "foo"
834
- - when 12; "bar"
835
- = var
836
- HAML
837
-
838
- assert_equal(<<HTML, render(<<HAML))
839
- bar
840
- HTML
841
- - var = case 12
842
- - when 1
843
- - "foo"
844
- - when 12
845
- - "bar"
846
- = var
847
- HAML
848
-
849
- assert_equal(<<HTML, render(<<HAML))
850
- bar
851
- HTML
852
- - var = case 12
853
- - when 1
854
- - "foo"
855
- - when 12
856
- - "bar"
857
- = var
858
- HAML
859
- end
860
-
861
- def test_nested_case_assigned_to_var
862
- assert_equal(<<HTML, render(<<HAML))
863
- bar
864
- HTML
865
- - if true
866
- - var = case 12
867
- - when 1; "foo"
868
- - when 12; "bar"
869
- = var
870
- HAML
871
- end
872
-
873
- def test_case_assigned_to_multiple_vars
874
- assert_equal(<<HTML, render(<<HAML))
875
- bar
876
- bip
877
- HTML
878
- - var, vip = case 12
879
- - when 1; ["foo", "baz"]
880
- - when 12; ["bar", "bip"]
881
- = var
882
- = vip
883
- HAML
884
- end
885
-
886
- def test_if_assigned_to_var
887
- assert_equal(<<HTML, render(<<HAML))
888
- foo
889
- HTML
890
- - var = if false
891
- - else
892
- - "foo"
893
- = var
894
- HAML
895
-
896
- assert_equal(<<HTML, render(<<HAML))
897
- foo
898
- HTML
899
- - var = if false
900
- - elsif 12 == 12
901
- - "foo"
902
- - elsif 14 == 14; "bar"
903
- - else
904
- - "baz"
905
- = var
906
- HAML
907
-
908
- assert_equal(<<HTML, render(<<HAML))
909
- foo
910
- HTML
911
- - var = if false
912
- - "bar"
913
- - else
914
- - "foo"
915
- = var
916
- HAML
917
- end
918
-
919
- def test_case_with_newline_after_case
920
- assert_equal(<<HTML, render(<<HAML))
921
- foo
922
- HTML
923
- - case 1
924
-
925
- - when 1
926
- foo
927
- - when 2
928
- bar
929
- HAML
930
-
931
- assert_equal(<<HTML, render(<<HAML))
932
- bar
933
- HTML
934
- - case 2
935
-
936
- - when 1
937
- foo
938
- - when 2
939
- bar
940
- HAML
941
- end
942
-
943
- def test_escape_html_with_interpolated_if_statement
944
- assert_equal(<<HTML, render(<<HAML, :escape_html => true))
945
- foo,
946
- HTML
947
- foo\#{"," if true}
948
- HAML
949
- end
950
-
951
- # HTML escaping tests
952
-
953
- def test_ampersand_equals_should_escape
954
- assert_equal("<p>\nfoo &amp; bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
955
- end
956
-
957
- def test_ampersand_equals_inline_should_escape
958
- assert_equal("<p>foo &amp; bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
959
- end
960
-
961
- def test_ampersand_equals_should_escape_before_preserve
962
- assert_equal("<textarea>foo&#x000A;bar</textarea>\n", render('%textarea&= "foo\nbar"', :escape_html => false))
963
- end
964
-
965
- def test_bang_equals_should_not_escape
966
- assert_equal("<p>\nfoo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
967
- end
968
-
969
- def test_bang_equals_inline_should_not_escape
970
- assert_equal("<p>foo & bar</p>\n", render("%p!= 'foo & bar'", :escape_html => true))
971
- end
972
-
973
- def test_static_attributes_should_be_escaped
974
- assert_equal("<img class='atlantis' style='ugly&amp;stupid'>\n",
975
- render("%img.atlantis{:style => 'ugly&stupid'}"))
976
- assert_equal("<div class='atlantis' style='ugly&amp;stupid'>foo</div>\n",
977
- render(".atlantis{:style => 'ugly&stupid'} foo"))
978
- assert_equal("<p class='atlantis' style='ugly&amp;stupid'>foo</p>\n",
979
- render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'"))
980
- end
981
-
982
- def test_dynamic_attributes_should_be_escaped
983
- assert_equal("<img alt='' src='&amp;foo.png'>\n",
984
- render("%img{:width => nil, :src => '&foo.png', :alt => String.new}"))
985
- assert_equal("<p alt='' src='&amp;foo.png'>foo</p>\n",
986
- render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo"))
987
- assert_equal("<div alt='' src='&amp;foo.png'>foo</div>\n",
988
- render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'"))
989
- end
990
-
991
- def test_string_double_equals_should_be_esaped
992
- assert_equal("<p>4&&lt;</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true))
993
- assert_equal("<p>4&<</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false))
994
- end
995
-
996
- def test_escaped_inline_string_double_equals
997
- assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true))
998
- assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false))
999
- end
1000
-
1001
- def test_unescaped_inline_string_double_equals
1002
- assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true))
1003
- assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false))
1004
- end
1005
-
1006
- def test_escaped_string_double_equals
1007
- assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
1008
- assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
1009
- end
1010
-
1011
- def test_unescaped_string_double_equals
1012
- assert_equal("<p>\n4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
1013
- assert_equal("<p>\n4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
1014
- end
1015
-
1016
- def test_string_interpolation_should_be_esaped
1017
- assert_equal("<p>4&&lt;</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => true))
1018
- assert_equal("<p>4&<</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => false))
1019
- end
1020
-
1021
- def test_escaped_inline_string_interpolation
1022
- assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true))
1023
- assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false))
1024
- end
1025
-
1026
- def test_unescaped_inline_string_interpolation
1027
- assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true))
1028
- assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false))
1029
- end
1030
-
1031
- def test_escaped_string_interpolation
1032
- assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
1033
- assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
1034
- end
1035
-
1036
- def test_escaped_string_interpolation_with_no_space
1037
- assert_equal("&lt;br&gt;\n", render('&#{"<br>"}'))
1038
- assert_equal("<span>&lt;br&gt;</span>\n", render('%span&#{"<br>"}'))
1039
- end
1040
-
1041
- def test_unescaped_string_interpolation
1042
- assert_equal("<p>\n4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
1043
- assert_equal("<p>\n4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
1044
- end
1045
-
1046
- def test_unescaped_string_interpolation_with_no_space
1047
- assert_equal("<br>\n", render('!#{"<br>"}'))
1048
- assert_equal("<span><br></span>\n", render('%span!#{"<br>"}'))
1049
- end
1050
-
1051
- def test_scripts_should_respect_escape_html_option
1052
- assert_equal("<p>\nfoo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
1053
- assert_equal("<p>\nfoo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
1054
- end
1055
-
1056
- def test_inline_scripts_should_respect_escape_html_option
1057
- assert_equal("<p>foo &amp; bar</p>\n", render("%p= 'foo & bar'", :escape_html => true))
1058
- assert_equal("<p>foo & bar</p>\n", render("%p= 'foo & bar'", :escape_html => false))
1059
- end
1060
-
1061
- def test_script_ending_in_comment_should_render_when_html_is_escaped
1062
- assert_equal("foo&amp;bar\n", render("= 'foo&bar' #comment", :escape_html => true))
1063
- end
1064
-
1065
- def test_script_with_if_shouldnt_output
1066
- assert_equal(<<HTML, render(<<HAML))
1067
- <p>foo</p>
1068
- <p></p>
1069
- HTML
1070
- %p= "foo"
1071
- %p= "bar" if false
1072
- HAML
1073
- end
1074
-
1075
- # Options tests
1076
-
1077
- def test_filename_and_line
1078
- begin
1079
- render("\n\n = abc", :filename => 'test', :line => 2)
1080
- rescue Exception => e
1081
- assert_kind_of Haml::SyntaxError, e
1082
- assert_match(/test:4/, e.backtrace.first)
1083
- end
1084
-
1085
- begin
1086
- render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
1087
- rescue Exception => e
1088
- assert_kind_of NoMethodError, e
1089
- backtrace = e.backtrace
1090
- backtrace.shift if rubinius?
1091
- assert_match(/test:6/, backtrace.first)
1092
- end
1093
- end
1094
-
1095
- def test_stop_eval
1096
- assert_equal("", render("= 'Hello'", :suppress_eval => true))
1097
- assert_equal("", render("- haml_concat 'foo'", :suppress_eval => true))
1098
- assert_equal("<div id='foo' yes='no'>\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
1099
- assert_equal("<div id='foo'>\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
1100
- assert_equal("<div>\n", render("%div[1]/", :suppress_eval => true))
1101
- assert_equal("", render(":ruby\n Kernel.puts 'hello'", :suppress_eval => true))
1102
- end
1103
-
1104
- def test_doctypes
1105
- assert_equal('<!DOCTYPE html>',
1106
- render('!!!', :format => :html5).strip)
1107
- assert_equal('<!DOCTYPE html>', render('!!! 5').strip)
1108
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
1109
- render('!!! strict', :format => :xhtml).strip)
1110
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
1111
- render('!!! frameset', :format => :xhtml).strip)
1112
- assert_equal('<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">',
1113
- render('!!! mobile', :format => :xhtml).strip)
1114
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
1115
- render('!!! basic', :format => :xhtml).strip)
1116
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
1117
- render('!!! transitional', :format => :xhtml).strip)
1118
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
1119
- render('!!!', :format => :xhtml).strip)
1120
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
1121
- render('!!! strict', :format => :html4).strip)
1122
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
1123
- render('!!! frameset', :format => :html4).strip)
1124
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
1125
- render('!!! transitional', :format => :html4).strip)
1126
- assert_equal('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
1127
- render('!!!', :format => :html4).strip)
1128
- end
1129
-
1130
- def test_attr_wrapper
1131
- assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
1132
- assert_equal("<p escaped=\"quo&quot;te\"></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
1133
- assert_equal("<p escaped=\"quo&#39;te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
1134
- assert_equal("<p escaped=\"q&#39;uo&quot;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
1135
- assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"', :format => :xhtml))
1136
- end
1137
-
1138
- def test_autoclose_option
1139
- assert_equal("<flaz foo='bar'>\n", render("%flaz{:foo => 'bar'}", :autoclose => ["flaz"]))
1140
- assert_equal(<<HTML, render(<<HAML, :autoclose => [/^flaz/]))
1141
- <flaz>
1142
- <flaznicate>
1143
- <flan></flan>
1144
- HTML
1145
- %flaz
1146
- %flaznicate
1147
- %flan
1148
- HAML
1149
- end
1150
-
1151
- def test_attrs_parsed_correctly
1152
- assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
1153
- assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
1154
- end
1155
-
1156
- def test_correct_parsing_with_brackets
1157
- assert_equal("<p class='foo'>{tada} foo</p>\n", render("%p{:class => 'foo'} {tada} foo"))
1158
- assert_equal("<p class='foo'>deep {nested { things }}</p>\n", render("%p{:class => 'foo'} deep {nested { things }}"))
1159
- assert_equal("<p class='bar foo'>{a { d</p>\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d"))
1160
- assert_equal("<p foo='bar'>a}</p>\n", render("%p{:foo => 'bar'} a}"))
1161
-
1162
- foo = []
1163
- foo[0] = Struct.new('Foo', :id).new
1164
- assert_equal("<p class='struct_foo' id='struct_foo_new'>New User]</p>\n",
1165
- render("%p[foo[0]] New User]", :locals => {:foo => foo}))
1166
- assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_new'>New User]</p>\n",
1167
- render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
1168
-
1169
- foo[0].id = 1
1170
- assert_equal("<p class='struct_foo' id='struct_foo_1'>New User]</p>\n",
1171
- render("%p[foo[0]] New User]", :locals => {:foo => foo}))
1172
- assert_equal("<p class='prefix_struct_foo' id='prefix_struct_foo_1'>New User]</p>\n",
1173
- render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo}))
1174
- end
1175
-
1176
- def test_empty_attrs
1177
- assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => '' } empty"))
1178
- assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => x } empty", :locals => {:x => ''}))
1179
- end
1180
-
1181
- def test_nil_attrs
1182
- assert_equal("<p>nil</p>\n", render("%p{ :attr => nil } nil"))
1183
- assert_equal("<p>nil</p>\n", render("%p{ :attr => x } nil", :locals => {:x => nil}))
1184
- end
1185
-
1186
- def test_nil_id_with_syntactic_id
1187
- assert_equal("<p id='foo'>nil</p>\n", render("%p#foo{:id => nil} nil"))
1188
- assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => 'bar'}, :id => nil} nil"))
1189
- assert_equal("<p id='foo_bar'>nil</p>\n", render("%p#foo{{:id => nil}, :id => 'bar'} nil"))
1190
- end
1191
-
1192
- def test_nil_class_with_syntactic_class
1193
- assert_equal("<p class='foo'>nil</p>\n", render("%p.foo{:class => nil} nil"))
1194
- assert_equal("<p class='bar foo'>nil</p>\n", render("%p.bar.foo{:class => nil} nil"))
1195
- assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => 'bar'}, :class => nil} nil"))
1196
- assert_equal("<p class='bar foo'>nil</p>\n", render("%p.foo{{:class => nil}, :class => 'bar'} nil"))
1197
- end
1198
-
1199
- def test_locals
1200
- assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
1201
- end
1202
-
1203
- def test_dynamic_attrs_shouldnt_register_as_literal_values
1204
- assert_equal("<p a='b2c'></p>\n", render('%p{:a => "b#{1 + 1}c"}'))
1205
- assert_equal("<p a='b2c'></p>\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}"))
1206
- end
1207
-
1208
- def test_dynamic_attrs_with_self_closed_tag
1209
- assert_equal("<a b='2'>\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n"))
1210
- end
1211
-
1212
- EXCEPTION_MAP.each do |key, value|
1213
- define_method("test_exception (#{key.inspect})") do
1214
- begin
1215
- silence_warnings do
1216
- render(key, :filename => "(test_exception (#{key.inspect}))")
1217
- end
1218
- rescue Exception => err
1219
- value = [value] unless value.is_a?(Array)
1220
- expected_message, line_no = value
1221
- line_no ||= key.split("\n").length
1222
-
1223
-
1224
- if expected_message == :compile
1225
- assert_match(/(compile error|syntax error|unterminated string|expecting)/, err.message, "Line: #{key}")
1226
- else
1227
- assert_equal(expected_message, err.message, "Line: #{key}")
1228
- end
1229
-
1230
- else
1231
- assert(false, "Exception not raised for\n#{key}")
1232
- end
1233
- end
1234
- end
1235
-
1236
- def test_exception_line
1237
- render("a\nb\n!!!\n c\nd")
1238
- rescue Haml::SyntaxError => e
1239
- assert_equal("(test_exception_line):4", e.backtrace[0])
1240
- else
1241
- assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
1242
- end
1243
-
1244
- def test_exception
1245
- render("%p\n hi\n %a= undefined\n= 12")
1246
- rescue Exception => e
1247
- backtrace = e.backtrace
1248
- backtrace.shift if rubinius?
1249
- assert_match("(test_exception):3", backtrace[0])
1250
- else
1251
- # Test failed... should have raised an exception
1252
- assert(false)
1253
- end
1254
-
1255
- def test_compile_error
1256
- render("a\nb\n- fee)\nc")
1257
- rescue Exception => e
1258
- assert_match(/\(test_compile_error\):3:/i, e.message)
1259
- assert_match(/(syntax error|expecting \$end)/i, e.message)
1260
- else
1261
- assert(false, '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1262
- end
1263
-
1264
- def test_unbalanced_brackets
1265
- render('foo #{1 + 5} foo #{6 + 7 bar #{8 + 9}')
1266
- rescue Haml::SyntaxError => e
1267
- assert_equal(Haml::Error.message(:unbalanced_brackets), e.message)
1268
- end
1269
-
1270
- def test_single_line_comments_are_interpolated
1271
- assert_equal("<!-- Hello 2 -->\n",
1272
- render('/ Hello #{1 + 1}'))
1273
- end
1274
-
1275
- def test_single_line_comments_are_not_interpolated_with_suppress_eval
1276
- assert_equal("<!-- -->\n",
1277
- render('/ Hello #{1 + 1}', :suppress_eval => true))
1278
- end
1279
-
1280
- def test_single_line_comments_with_interpolation_dont_break_tabulation
1281
- assert_equal("<!-- Hello 2 -->\nconcatted\n",
1282
- render("/ Hello \#{1 + 1}\n- haml_concat 'concatted'"))
1283
- end
1284
-
1285
- def test_balanced_conditional_comments
1286
- assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
1287
- render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
1288
- end
1289
-
1290
- def test_downlevel_revealed_conditional_comments
1291
- assert_equal("<!--[if !IE]><!--> A comment <!--<![endif]-->\n",
1292
- render("/![if !IE] A comment"))
1293
- end
1294
-
1295
- def test_downlevel_revealed_conditional_comments_block
1296
- assert_equal("<!--[if !IE]><!-->\nA comment\n<!--<![endif]-->\n",
1297
- render("/![if !IE]\n A comment"))
1298
- end
1299
-
1300
- def test_local_assigns_dont_modify_class
1301
- assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
1302
- assert_nil(defined?(foo))
1303
- end
1304
-
1305
- def test_object_ref_with_nil_id
1306
- user = User.new
1307
- assert_equal("<p class='struct_user' id='struct_user_new'>New User</p>\n",
1308
- render("%p[user] New User", :locals => {:user => user}))
1309
- end
1310
-
1311
- def test_object_ref_before_attrs
1312
- user = User.new 42
1313
- assert_equal("<p class='struct_user' id='struct_user_42' style='width: 100px;'>New User</p>\n",
1314
- render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user}))
1315
- end
1316
-
1317
- def test_object_ref_with_custom_haml_class
1318
- custom = CustomHamlClass.new 42
1319
- assert_equal("<p class='my_thing' id='my_thing_42' style='width: 100px;'>My Thing</p>\n",
1320
- render("%p[custom]{:style => 'width: 100px;'} My Thing", :locals => {:custom => custom}))
1321
- end
1322
-
1323
- def test_object_ref_with_multiple_ids
1324
- cpk_record = CpkRecord.new([42,6,9])
1325
- assert_equal("<p class='struct_cpk_record' id='struct_cpk_record_42_6_9' style='width: 100px;'>CPK Record</p>\n",
1326
- render("%p[cpk_record]{:style => 'width: 100px;'} CPK Record", :locals => {:cpk_record => cpk_record}))
1327
- end
1328
-
1329
- def test_non_literal_attributes
1330
- assert_equal("<p a1='foo' a2='bar' a3='baz'></p>\n",
1331
- render("%p{a2, a1, :a3 => 'baz'}",
1332
- :locals => {:a1 => {:a1 => 'foo'}, :a2 => {:a2 => 'bar'}}))
1333
- end
1334
-
1335
- def test_render_should_accept_a_binding_as_scope
1336
- string = "This is a string!"
1337
- string.instance_variable_set(:@var, "Instance variable")
1338
- b = string.instance_eval do
1339
- var = "Local variable"
1340
- # Silence unavoidable warning; Ruby doesn't know we're going to use this
1341
- # later.
1342
- nil if var
1343
- binding
1344
- end
1345
-
1346
- assert_equal("<p>THIS IS A STRING!</p>\n<p>Instance variable</p>\n<p>Local variable</p>\n",
1347
- render("%p= upcase\n%p= @var\n%p= var", :scope => b))
1348
- end
1349
-
1350
- def test_yield_should_work_with_binding
1351
- assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 })
1352
- end
1353
-
1354
- def test_yield_should_work_with_def_method
1355
- s = "foo"
1356
- engine("= yield\n= upcase").def_method(s, :render)
1357
- assert_equal("12\nFOO\n", s.render { 12 })
1358
- end
1359
-
1360
- def test_def_method_with_module
1361
- engine("= yield\n= upcase").def_method(String, :render_haml)
1362
- assert_equal("12\nFOO\n", "foo".render_haml { 12 })
1363
- end
1364
-
1365
- def test_def_method_locals
1366
- obj = Object.new
1367
- engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
1368
- assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", obj.render(:foo => 1, :baz => 2, :boom => 3))
1369
- end
1370
-
1371
- def test_render_proc_locals
1372
- proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
1373
- assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", proc[:foo => 1, :baz => 2, :boom => 3])
1374
- end
1375
-
1376
- def test_render_proc_with_binding
1377
- assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call)
1378
- end
1379
-
1380
- def test_haml_buffer_gets_reset_even_with_exception
1381
- scope = Object.new
1382
- render("- raise Haml::Error", :scope => scope)
1383
- assert(false, "Expected exception")
1384
- rescue Exception
1385
- assert_nil(scope.send(:haml_buffer))
1386
- end
1387
-
1388
- def test_def_method_haml_buffer_gets_reset_even_with_exception
1389
- scope = Object.new
1390
- engine("- raise Haml::Error").def_method(scope, :render)
1391
- scope.render
1392
- assert(false, "Expected exception")
1393
- rescue Exception
1394
- assert_nil(scope.send(:haml_buffer))
1395
- end
1396
-
1397
- def test_render_proc_haml_buffer_gets_reset_even_with_exception
1398
- scope = Object.new
1399
- proc = engine("- raise Haml::Error").render_proc(scope)
1400
- proc.call
1401
- assert(false, "Expected exception")
1402
- rescue Exception
1403
- assert_nil(scope.send(:haml_buffer))
1404
- end
1405
-
1406
- def test_render_proc_should_raise_haml_syntax_error_not_ruby_syntax_error
1407
- assert_raises(Haml::SyntaxError) do
1408
- Haml::Engine.new("%p{:foo => !}").render_proc(Object.new, :foo).call
1409
- end
1410
- end
1411
-
1412
- def test_render_should_raise_haml_syntax_error_not_ruby_syntax_error
1413
- assert_raises(Haml::SyntaxError) do
1414
- Haml::Engine.new("%p{:foo => !}").render
1415
- end
1416
- end
1417
-
1418
- def test_spacing_inside_tag
1419
- assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
1420
- render("#outer\n #inner\n %p hello world"))
1421
-
1422
- assert_equal("<p>#{'s' * 75}</p>\n",
1423
- render("%p #{'s' * 75}"))
1424
-
1425
- assert_equal("<p>#{'s' * 75}</p>\n",
1426
- render("%p= 's' * 75"))
1427
- end
1428
-
1429
- def test_remove_whitespace_true
1430
- assert_equal("<div id='outer'><div id='inner'><p>hello world</p></div></div>",
1431
- render("#outer\n #inner\n %p hello world", :remove_whitespace => true))
1432
- assert_equal("<p>hello world<pre>foo bar\nbaz</pre></p>", render(<<HAML, :remove_whitespace => true))
1433
- %p
1434
- hello world
1435
- %pre
1436
- foo bar
1437
- baz
1438
- HAML
1439
- assert_equal("<div><span>foo</span> <span>bar</span></div>",
1440
- render('%div <span>foo</span> <span>bar</span>', :remove_whitespace => true))
1441
- end
1442
-
1443
- def test_auto_preserve
1444
- assert_equal("<pre>foo&#x000A;bar</pre>\n", render('%pre="foo\nbar"'))
1445
- assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar"))
1446
- end
1447
-
1448
- def test_xhtml_output_option
1449
- assert_equal "<p>\n<br />\n</p>\n", render("%p\n %br", :format => :xhtml)
1450
- assert_equal "<a />\n", render("%a/", :format => :xhtml)
1451
- end
1452
-
1453
- def test_arbitrary_output_option
1454
- assert_raises_message(Haml::Error, "Invalid output format :html1") do
1455
- engine("%br", :format => :html1)
1456
- end
1457
- end
1458
-
1459
- def test_static_hashes
1460
- assert_equal("<a b='a =&gt; b'></a>\n", render("%a{:b => 'a => b'}", :suppress_eval => true))
1461
- assert_equal("<a b='a, b'></a>\n", render("%a{:b => 'a, b'}", :suppress_eval => true))
1462
- assert_equal("<a b='a\tb'></a>\n", render('%a{:b => "a\tb"}', :suppress_eval => true))
1463
- assert_equal("<a b='a\#{foo}b'></a>\n", render('%a{:b => "a\\#{foo}b"}', :suppress_eval => true))
1464
- assert_equal("<a b='#f00'></a>\n", render("%a{:b => '#f00'}", :suppress_eval => true))
1465
- end
1466
-
1467
- def test_dynamic_hashes_with_suppress_eval
1468
- assert_equal("<a></a>\n", render('%a{:b => "a #{1 + 1} b", :c => "d"}', :suppress_eval => true))
1469
- end
1470
-
1471
- def test_interpolates_instance_vars_in_attribute_values
1472
- scope = Object.new
1473
- scope.instance_variable_set :@foo, 'bar'
1474
- assert_equal("<a b='a bar b'></a>\n", render('%a{:b => "a #@foo b"}', :scope => scope))
1475
- end
1476
-
1477
- def test_interpolates_global_vars_in_attribute_values
1478
- # make sure the value isn't just interpolated in during template compilation
1479
- engine = Haml::Engine.new('%a{:b => "a #$global_var_for_testing b"}')
1480
- $global_var_for_testing = 'bar'
1481
- assert_equal("<a b='a bar b'></a>\n", engine.to_html)
1482
- ensure
1483
- $global_var_for_testing = nil
1484
- end
1485
-
1486
- def test_utf8_attrs
1487
- assert_equal("<a href='héllo'></a>\n", render("%a{:href => 'héllo'}"))
1488
- assert_equal("<a href='héllo'></a>\n", render("%a(href='héllo')"))
1489
- end
1490
-
1491
- # HTML 4.0
1492
-
1493
- def test_html_has_no_self_closing_tags
1494
- assert_equal "<p>\n<br>\n</p>\n", render("%p\n %br", :format => :html4)
1495
- assert_equal "<br>\n", render("%br/", :format => :html4)
1496
- end
1497
-
1498
- def test_html_renders_empty_node_with_closing_tag
1499
- assert_equal "<div class='foo'></div>\n", render(".foo", :format => :html4)
1500
- end
1501
-
1502
- def test_html_doesnt_add_slash_to_self_closing_tags
1503
- assert_equal "<a>\n", render("%a/", :format => :html4)
1504
- assert_equal "<a foo='2'>\n", render("%a{:foo => 1 + 1}/", :format => :html4)
1505
- assert_equal "<meta>\n", render("%meta", :format => :html4)
1506
- assert_equal "<meta foo='2'>\n", render("%meta{:foo => 1 + 1}", :format => :html4)
1507
- end
1508
-
1509
- def test_html_ignores_xml_prolog_declaration
1510
- assert_equal "", render('!!! XML', :format => :html4)
1511
- end
1512
-
1513
- def test_html_has_different_doctype
1514
- assert_equal %{<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n},
1515
- render('!!!', :format => :html4)
1516
- end
1517
-
1518
- # because anything before the doctype triggers quirks mode in IE
1519
- def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
1520
- refute_match(/^\s+/, render("!!! xml\n!!!", :format => :html4))
1521
- end
1522
-
1523
- # HTML5
1524
- def test_html5_doctype
1525
- assert_equal %{<!DOCTYPE html>\n}, render('!!!', :format => :html5)
1526
- end
1527
-
1528
- # HTML5 custom data attributes
1529
- def test_html5_data_attributes_without_hyphenation
1530
- assert_equal("<div data-author_id='123' data-biz='baz' data-foo='bar'></div>\n",
1531
- render("%div{:data => {:author_id => 123, :foo => 'bar', :biz => 'baz'}}",
1532
- :hyphenate_data_attrs => false))
1533
-
1534
- assert_equal("<div data-one_plus_one='2'></div>\n",
1535
- render("%div{:data => {:one_plus_one => 1+1}}",
1536
- :hyphenate_data_attrs => false))
1537
-
1538
- assert_equal("<div data-foo='Here&#39;s a &quot;quoteful&quot; string.'></div>\n",
1539
- render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}},
1540
- :hyphenate_data_attrs => false)) #'
1541
- end
1542
-
1543
- def test_html5_data_attributes_with_hyphens
1544
- assert_equal("<div data-foo-bar='blip'></div>\n",
1545
- render("%div{:data => {:foo_bar => 'blip'}}"))
1546
- assert_equal("<div data-baz='bang' data-foo-bar='blip'></div>\n",
1547
- render("%div{:data => {:foo_bar => 'blip', :baz => 'bang'}}"))
1548
- end
1549
-
1550
- def test_html5_arbitrary_hash_valued_attributes_with
1551
- assert_equal("<div aria-foo='blip'></div>\n",
1552
- render("%div{:aria => {:foo => 'blip'}}"))
1553
- assert_equal("<div foo-baz='bang'></div>\n",
1554
- render("%div{:foo => {:baz => 'bang'}}"))
1555
- end
1556
-
1557
- def test_arbitrary_attribute_hash_merging
1558
- assert_equal(%Q{<a aria-baz='qux' aria-foo='bar'></a>\n}, render(<<-HAML))
1559
- - h1 = {:aria => {:foo => :bar}}
1560
- - h2 = {:baz => :qux}
1561
- %a{h1, :aria => h2}
1562
- HAML
1563
- end
1564
-
1565
- def test_hash_method_call_in_attributes
1566
- assert_equal(%Q{<a foo='bar' hoge='fuga'></a>\n}, render(<<-HAML))
1567
- - hash = {:hoge => :fuga}
1568
- %a{{foo: 'bar'}.merge(hash)}
1569
- HAML
1570
- end
1571
-
1572
- def test_html5_data_attributes_with_nested_hash
1573
- assert_equal("<div data-a-b='c'></div>\n", render(<<-HAML))
1574
- - hash = {:a => {:b => 'c'}}
1575
- - hash[:d] = hash
1576
- %div{:data => hash}
1577
- HAML
1578
- end
1579
-
1580
- def test_html5_data_attributes_with_nested_hash_and_without_hyphenation
1581
- assert_equal("<div data-a_b='c'></div>\n", render(<<-HAML, :hyphenate_data_attrs => false))
1582
- - hash = {:a => {:b => 'c'}}
1583
- - hash[:d] = hash
1584
- %div{:data => hash}
1585
- HAML
1586
- end
1587
-
1588
- def test_html5_data_attributes_with_multiple_defs
1589
- # Should always use the more-explicit attribute
1590
- assert_equal("<div data-foo='second'></div>\n",
1591
- render("%div{:data => {:foo => 'first'}, 'data-foo' => 'second'}"))
1592
- assert_equal("<div data-foo='first'></div>\n",
1593
- render("%div{'data-foo' => 'first', :data => {:foo => 'second'}}"))
1594
- end
1595
-
1596
- def test_html5_data_attributes_with_attr_method
1597
- obj = Object.new
1598
- def obj.data_hash
1599
- {:data => {:foo => "bar", :baz => "bang"}}
1600
- end
1601
-
1602
- def obj.data_val
1603
- {:data => "dat"}
1604
- end
1605
-
1606
- assert_equal("<div data-baz='bang' data-brat='wurst' data-foo='blip'></div>\n",
1607
- render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1608
- assert_equal("<div data-baz='bang' data-foo='blip'></div>\n",
1609
- render("%div{data_hash, 'data-foo' => 'blip'}", scope: obj))
1610
- assert_equal("<div data-baz='bang' data-foo='bar' data='dat'></div>\n",
1611
- render("%div{data_hash, :data => 'dat'}", scope: obj))
1612
- assert_equal("<div data-brat='wurst' data-foo='blip' data='dat'></div>\n",
1613
- render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1614
- end
1615
-
1616
- def test_html5_data_attributes_with_identical_attribute_values
1617
- assert_equal("<div data-x='50' data-y='50'></div>\n",
1618
- render("%div{:data => {:x => 50, :y => 50}}"))
1619
- end
1620
-
1621
- def test_xml_doc_using_html5_format_and_mime_type
1622
- assert_equal(<<XML, render(<<HAML, { :format => :html5, :mime_type => 'text/xml' }))
1623
- <?xml version='1.0' encoding='utf-8' ?>
1624
- <root>
1625
- <element />
1626
- <hr />
1627
- </root>
1628
- XML
1629
- !!! XML
1630
- %root
1631
- %element/
1632
- %hr
1633
- HAML
1634
- end
1635
-
1636
- def test_xml_doc_using_html4_format_and_mime_type
1637
- assert_equal(<<XML, render(<<HAML, { :format => :html4, :mime_type => 'text/xml' }))
1638
- <?xml version='1.0' encoding='utf-8' ?>
1639
- <root>
1640
- <element />
1641
- <hr />
1642
- </root>
1643
- XML
1644
- !!! XML
1645
- %root
1646
- %element/
1647
- %hr
1648
- HAML
1649
- end
1650
-
1651
- # New attributes
1652
-
1653
- def test_basic_new_attributes
1654
- assert_equal("<a>bar</a>\n", render("%a() bar"))
1655
- assert_equal("<a href='foo'>bar</a>\n", render("%a(href='foo') bar"))
1656
- assert_equal("<a b='c' c='d' d='e'>baz</a>\n", render(%q{%a(b="c" c='d' d="e") baz}))
1657
- end
1658
-
1659
- def test_new_attribute_ids
1660
- assert_equal("<div id='foo_bar'></div>\n", render("#foo(id='bar')"))
1661
- assert_equal("<div id='foo_baz_bar'></div>\n", render("#foo{:id => 'bar'}(id='baz')"))
1662
- assert_equal("<div id='foo_baz_bar'></div>\n", render("#foo(id='baz'){:id => 'bar'}"))
1663
- foo = User.new(42)
1664
- assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1665
- render("#foo(id='baz'){:id => 'bar'}[foo]", :locals => {:foo => foo}))
1666
- assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1667
- render("#foo(id='baz')[foo]{:id => 'bar'}", :locals => {:foo => foo}))
1668
- assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1669
- render("#foo[foo](id='baz'){:id => 'bar'}", :locals => {:foo => foo}))
1670
- assert_equal("<div class='struct_user' id='foo_baz_bar_struct_user_42'></div>\n",
1671
- render("#foo[foo]{:id => 'bar'}(id='baz')", :locals => {:foo => foo}))
1672
- end
1673
-
1674
- def test_new_attribute_classes
1675
- assert_equal("<div class='bar foo'></div>\n", render(".foo(class='bar')"))
1676
- assert_equal("<div class='bar baz foo'></div>\n", render(".foo{:class => 'bar'}(class='baz')"))
1677
- assert_equal("<div class='bar baz foo'></div>\n", render(".foo(class='baz'){:class => 'bar'}"))
1678
- foo = User.new(42)
1679
- assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1680
- render(".foo(class='baz'){:class => 'bar'}[foo]", :locals => {:foo => foo}))
1681
- assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1682
- render(".foo[foo](class='baz'){:class => 'bar'}", :locals => {:foo => foo}))
1683
- assert_equal("<div class='bar baz foo struct_user' id='struct_user_42'></div>\n",
1684
- render(".foo[foo]{:class => 'bar'}(class='baz')", :locals => {:foo => foo}))
1685
- end
1686
-
1687
- def test_dynamic_new_attributes
1688
- assert_equal("<a href='12'>bar</a>\n", render("%a(href=foo) bar", :locals => {:foo => 12}))
1689
- assert_equal("<a b='12' c='13' d='14'>bar</a>\n", render("%a(b=b c='13' d=d) bar", :locals => {:b => 12, :d => 14}))
1690
- end
1691
-
1692
- def test_new_attribute_interpolation
1693
- assert_equal("<a href='12'>bar</a>\n", render('%a(href="1#{1 + 1}") bar'))
1694
- assert_equal("<a href='2: 2, 3: 3'>bar</a>\n", render(%q{%a(href='2: #{1 + 1}, 3: #{foo}') bar}, :locals => {:foo => 3}))
1695
- assert_equal(%Q{<a href='1\#{1 + 1}'>bar</a>\n}, render('%a(href="1\#{1 + 1}") bar'))
1696
- end
1697
-
1698
- def test_truthy_new_attributes
1699
- assert_equal("<a href='href'>bar</a>\n", render("%a(href) bar", :format => :xhtml))
1700
- assert_equal("<a bar='baz' href>bar</a>\n", render("%a(href bar='baz') bar", :format => :html5))
1701
- assert_equal("<a href>bar</a>\n", render("%a(href=true) bar"))
1702
- assert_equal("<a>bar</a>\n", render("%a(href=false) bar"))
1703
- end
1704
-
1705
- def test_new_attribute_parsing
1706
- assert_equal("<a a2='b2'>bar</a>\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'}))
1707
- assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1708
- assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1709
- assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1710
- assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1711
- assert_equal("<a a:b='foo'>bar</a>\n", render("%a(a:b='foo') bar"))
1712
- assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = 'foo' b = 'bar') bar"))
1713
- assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'}))
1714
- assert_equal("<a a='foo'>(b='bar')</a>\n", render("%a(a='foo')(b='bar')"))
1715
- assert_equal("<a a='foo)bar'>baz</a>\n", render("%a(a='foo)bar') baz"))
1716
- assert_equal("<a a='foo'>baz</a>\n", render("%a( a = 'foo' ) baz"))
1717
- end
1718
-
1719
- def test_new_attribute_escaping
1720
- assert_equal(%Q{<a a='foo &quot; bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1721
- assert_equal(%Q{<a a='foo \\&quot; bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1722
-
1723
- assert_equal(%Q{<a a='foo &#39; bar'>bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1724
- assert_equal(%Q{<a a='foo \\&#39; bar'>bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1725
-
1726
- assert_equal(%Q{<a a='foo \\ bar'>bar</a>\n}, render(%q{%a(a="foo \\\\ bar") bar}))
1727
- assert_equal(%Q{<a a='foo \#{1 + 1} bar'>bar</a>\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar}))
1728
- end
1729
-
1730
- def test_multiline_new_attribute
1731
- assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'\n c='d') bar"))
1732
- assert_equal("<a a='b' b='c' c='d' d='e' e='f' f='j'>bar</a>\n",
1733
- render("%a(a='b' b='c'\n c='d' d=e\n e='f' f='j') bar", :locals => {:e => 'e'}))
1734
- end
1735
-
1736
- def test_new_and_old_attributes
1737
- assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(a='b'){:c => 'd'} bar"))
1738
- assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:c => 'd'}(a='b') bar"))
1739
- assert_equal("<a a='b' c='d'>bar</a>\n", render("%a(c='d'){:a => 'b'} bar"))
1740
- assert_equal("<a a='b' c='d'>bar</a>\n", render("%a{:a => 'b'}(c='d') bar"))
1741
-
1742
- # Old-style always takes precedence over new-style,
1743
- # because theoretically old-style could have arbitrary end-of-method-call syntax.
1744
- assert_equal("<a a='b'>bar</a>\n", render("%a{:a => 'b'}(a='d') bar"))
1745
- assert_equal("<a a='b'>bar</a>\n", render("%a(a='d'){:a => 'b'} bar"))
1746
-
1747
- assert_equal("<a a='b' b='c' c='d' d='e'>bar</a>\n",
1748
- render("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar"))
1749
-
1750
- locals = {:b => 'b', :d => 'd'}
1751
- assert_equal("<p a='b' c='d'></p>\n", render("%p{:a => b}(c=d)", :locals => locals))
1752
- assert_equal("<p a='b' c='d'></p>\n", render("%p(a=b){:c => d}", :locals => locals))
1753
-
1754
- assert_equal("<p id='b_d'></p>\n<p id='b_d'></p>\n", render("%p(id=b){id:d}\n%p(id=b){id:d}", locals: locals))
1755
- end
1756
-
1757
- # Ruby Multiline
1758
-
1759
- def test_silent_ruby_multiline
1760
- assert_equal(<<HTML, render(<<HAML))
1761
- bar, baz, bang
1762
- <p>foo</p>
1763
- HTML
1764
- - foo = ["bar",
1765
- "baz",
1766
- "bang"]
1767
- = foo.join(", ")
1768
- %p foo
1769
- HAML
1770
- end
1771
-
1772
- def test_loud_ruby_multiline
1773
- assert_equal(<<HTML, render(<<HAML))
1774
- bar, baz, bang
1775
- <p>foo</p>
1776
- <p>bar</p>
1777
- HTML
1778
- = ["bar",
1779
- "baz",
1780
- "bang"].join(", ")
1781
- %p foo
1782
- %p bar
1783
- HAML
1784
- end
1785
-
1786
- def test_ruby_multiline_with_punctuated_methods_is_continuation
1787
- assert_equal(<<HTML, render(<<HAML))
1788
- bar, , true, bang
1789
- <p>foo</p>
1790
- <p>bar</p>
1791
- HTML
1792
- = ["bar",
1793
- " ".strip!,
1794
- "".empty?,
1795
- "bang"].join(", ")
1796
- %p foo
1797
- %p bar
1798
- HAML
1799
- end
1800
-
1801
- def test_ruby_character_literals_are_not_continuation
1802
- html = ",\n,\n<p>foo</p>\n"
1803
- assert_equal(html, render(<<HAML))
1804
- = ?,
1805
- = ?\,
1806
- %p foo
1807
- HAML
1808
- end
1809
-
1810
- def test_escaped_loud_ruby_multiline
1811
- assert_equal(<<HTML, render(<<HAML))
1812
- bar&lt;, baz, bang
1813
- <p>foo</p>
1814
- <p>bar</p>
1815
- HTML
1816
- &= ["bar<",
1817
- "baz",
1818
- "bang"].join(", ")
1819
- %p foo
1820
- %p bar
1821
- HAML
1822
- end
1823
-
1824
- def test_unescaped_loud_ruby_multiline
1825
- assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1826
- bar<, baz, bang
1827
- <p>foo</p>
1828
- <p>bar</p>
1829
- HTML
1830
- != ["bar<",
1831
- "baz",
1832
- "bang"].join(", ")
1833
- %p foo
1834
- %p bar
1835
- HAML
1836
- end
1837
-
1838
- def test_flattened_loud_ruby_multiline
1839
- assert_equal(<<HTML, render(<<HAML))
1840
- <pre>bar&#x000A;baz&#x000A;bang</pre>
1841
- <p>foo</p>
1842
- <p>bar</p>
1843
- HTML
1844
- ~ "<pre>" + ["bar",
1845
- "baz",
1846
- "bang"].join("\\n") + "</pre>"
1847
- %p foo
1848
- %p bar
1849
- HAML
1850
- end
1851
-
1852
- def test_loud_ruby_multiline_with_block
1853
- assert_equal(<<HTML, render(<<HAML))
1854
- #{%w[far faz fang]}<p>foo</p>
1855
- <p>bar</p>
1856
- HTML
1857
- = ["bar",
1858
- "baz",
1859
- "bang"].map do |str|
1860
- - str.gsub("ba",
1861
- "fa")
1862
- %p foo
1863
- %p bar
1864
- HAML
1865
- end
1866
-
1867
- def test_silent_ruby_multiline_with_block
1868
- assert_equal(<<HTML, render(<<HAML))
1869
- far
1870
- faz
1871
- fang
1872
- <p>foo</p>
1873
- <p>bar</p>
1874
- HTML
1875
- - ["bar",
1876
- "baz",
1877
- "bang"].map do |str|
1878
- = str.gsub("ba",
1879
- "fa")
1880
- %p foo
1881
- %p bar
1882
- HAML
1883
- end
1884
-
1885
- def test_ruby_multiline_in_tag
1886
- assert_equal(<<HTML, render(<<HAML))
1887
- <p>foo, bar, baz</p>
1888
- <p>foo</p>
1889
- <p>bar</p>
1890
- HTML
1891
- %p= ["foo",
1892
- "bar",
1893
- "baz"].join(", ")
1894
- %p foo
1895
- %p bar
1896
- HAML
1897
- end
1898
-
1899
- def test_escaped_ruby_multiline_in_tag
1900
- assert_equal(<<HTML, render(<<HAML))
1901
- <p>foo&lt;, bar, baz</p>
1902
- <p>foo</p>
1903
- <p>bar</p>
1904
- HTML
1905
- %p&= ["foo<",
1906
- "bar",
1907
- "baz"].join(", ")
1908
- %p foo
1909
- %p bar
1910
- HAML
1911
- end
1912
-
1913
- def test_unescaped_ruby_multiline_in_tag
1914
- assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1915
- <p>foo<, bar, baz</p>
1916
- <p>foo</p>
1917
- <p>bar</p>
1918
- HTML
1919
- %p!= ["foo<",
1920
- "bar",
1921
- "baz"].join(", ")
1922
- %p foo
1923
- %p bar
1924
- HAML
1925
- end
1926
-
1927
- def test_ruby_multiline_with_normal_multiline
1928
- assert_equal(<<HTML, render(<<HAML))
1929
- foobarbar, baz, bang
1930
- <p>foo</p>
1931
- <p>bar</p>
1932
- HTML
1933
- = "foo" + |
1934
- "bar" + |
1935
- ["bar", |
1936
- "baz",
1937
- "bang"].join(", ")
1938
- %p foo
1939
- %p bar
1940
- HAML
1941
- end
1942
-
1943
- def test_ruby_multiline_after_filter
1944
- assert_equal(<<HTML, render(<<HAML))
1945
- foo
1946
- bar
1947
- bar, baz, bang
1948
- <p>foo</p>
1949
- <p>bar</p>
1950
- HTML
1951
- :plain
1952
- foo
1953
- bar
1954
- = ["bar",
1955
- "baz",
1956
- "bang"].join(", ")
1957
- %p foo
1958
- %p bar
1959
- HAML
1960
- end
1961
-
1962
- # Encodings
1963
-
1964
- def test_utf_8_bom
1965
- assert_equal <<HTML, render(<<HAML)
1966
- <div class='foo'>
1967
- <p>baz</p>
1968
- </div>
1969
- HTML
1970
- \xEF\xBB\xBF.foo
1971
- %p baz
1972
- HAML
1973
- end
1974
-
1975
- def test_default_encoding
1976
- assert_equal(Encoding.find("utf-8"), render(<<HAML.encode("us-ascii")).encoding)
1977
- %p bar
1978
- %p foo
1979
- HAML
1980
- end
1981
-
1982
- def test_fake_ascii_encoding
1983
- assert_encoded_equal(<<HTML.force_encoding("ascii-8bit"), render(<<HAML, :encoding => "ascii-8bit"))
1984
- <p>bâr</p>
1985
- <p>föö</p>
1986
- HTML
1987
- %p bâr
1988
- %p föö
1989
- HAML
1990
- end
1991
-
1992
- def test_convert_template_render_proc
1993
- assert_converts_template_properly {|e| e.render_proc.call}
1994
- end
1995
-
1996
- def test_convert_template_render
1997
- assert_converts_template_properly {|e| e.render}
1998
- end
1999
-
2000
- def test_convert_template_def_method
2001
- assert_converts_template_properly do |e|
2002
- o = Object.new
2003
- e.def_method(o, :render)
2004
- o.render
2005
- end
2006
- end
2007
-
2008
- def test_encoding_error
2009
- render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
2010
- assert(false, "Expected exception")
2011
- rescue Haml::Error => e
2012
- assert_equal(3, e.line)
2013
- assert_match(/Invalid .* character/, e.message)
2014
- end
2015
-
2016
- def test_ascii_incompatible_encoding_error
2017
- template = "foo\nbar\nb_z".encode("utf-16le")
2018
- template[9] = "\xFE".force_encoding("utf-16le")
2019
- render(template)
2020
- assert(false, "Expected exception")
2021
- rescue Haml::Error => e
2022
- assert_equal(3, e.line)
2023
- assert_match(/Invalid .* character/, e.message)
2024
- end
2025
-
2026
- def test_same_coding_comment_as_encoding
2027
- assert_renders_encoded(<<HTML, <<HAML)
2028
- <p>bâr</p>
2029
- <p>föö</p>
2030
- HTML
2031
- -# coding: utf-8
2032
- %p bâr
2033
- %p föö
2034
- HAML
2035
- end
2036
-
2037
- def test_coding_comments
2038
- assert_valid_encoding_comment("-# coding: ibm866")
2039
- assert_valid_encoding_comment("-# CodINg: IbM866")
2040
- assert_valid_encoding_comment("-#coding:ibm866")
2041
- assert_valid_encoding_comment("-# CodINg= ibm866")
2042
- assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866")
2043
- assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$")
2044
- assert_valid_encoding_comment("-# -*- coding: ibm866")
2045
- assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah")
2046
- assert_valid_encoding_comment("-# -*- coding: ibm866 -*-")
2047
- assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-")
2048
- assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-')
2049
- assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
2050
- assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
2051
- assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-")
2052
- assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-")
2053
- assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz")
2054
- end
2055
-
2056
- def test_different_coding_than_system
2057
- assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866"))
2058
- <p>тАЬ</p>
2059
- HTML
2060
- %p тАЬ
2061
- HAML
2062
- end
2063
-
2064
- def test_block_spacing
2065
- begin
2066
- assert render(<<-HAML)
2067
- - foo = ["bar", "baz", "kni"]
2068
- - foo.each do | item |
2069
- = item
2070
- HAML
2071
- rescue ::SyntaxError
2072
- flunk("Should not have raised syntax error")
2073
- end
2074
- end
2075
-
2076
- def test_tracing
2077
- result = render('%p{:class => "hello"}', :trace => true, :filename => 'foo').strip
2078
- assert_equal "<p class='hello' data-trace='foo:1'></p>", result
2079
- end
2080
-
2081
- def test_unsafe_dynamic_attribute_name_raises_invalid_attribute_name_error
2082
- assert_raises(Haml::InvalidAttributeNameError) do
2083
- render(<<-HAML)
2084
- - params = { 'x /><script>alert(1);</script><div x' => 'hello' }
2085
- %div{ data: params }
2086
- HAML
2087
- end
2088
- end
2089
-
2090
- def test_unsafe_static_attribute_name_raises_invalid_attribute_name_error
2091
- assert_raises(Haml::InvalidAttributeNameError) do
2092
- render(<<-HAML)
2093
- %div{ 'x /><script>alert(1);</script><div x' => 'hello' }
2094
- HAML
2095
- end
2096
- end
2097
-
2098
- private
2099
-
2100
- def assert_valid_encoding_comment(comment)
2101
- assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866").force_encoding("UTF-8"))
2102
- <p>ЖЛЫ</p>
2103
- <p>тАЬ</p>
2104
- HTML
2105
- #{comment}
2106
- %p ЖЛЫ
2107
- %p тАЬ
2108
- HAML
2109
- end
2110
-
2111
- def assert_converts_template_properly
2112
- engine = Haml::Engine.new(<<HAML.encode("iso-8859-1"), :encoding => "macRoman")
2113
- %p bâr
2114
- %p föö
2115
- HAML
2116
- assert_encoded_equal(<<HTML.encode("macRoman"), yield(engine))
2117
- <p>bâr</p>
2118
- <p>föö</p>
2119
- HTML
2120
- end
2121
-
2122
- def assert_renders_encoded(html, haml)
2123
- result = render(haml)
2124
- assert_encoded_equal html, result
2125
- end
2126
-
2127
- def assert_encoded_equal(expected, actual)
2128
- assert_equal expected.encoding, actual.encoding
2129
- assert_equal expected, actual
2130
- end
2131
- end