locomotivecms-liquid 2.6.0 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +62 -5
  3. data/README.md +4 -4
  4. data/lib/liquid.rb +16 -12
  5. data/lib/liquid/block.rb +37 -118
  6. data/lib/liquid/block_body.rb +131 -0
  7. data/lib/liquid/condition.rb +28 -17
  8. data/lib/liquid/context.rb +94 -146
  9. data/lib/liquid/document.rb +16 -10
  10. data/lib/liquid/drop.rb +8 -5
  11. data/lib/liquid/drops/inherited_block_drop.rb +24 -0
  12. data/lib/liquid/errors.rb +44 -5
  13. data/lib/liquid/expression.rb +33 -0
  14. data/lib/liquid/file_system.rb +17 -6
  15. data/lib/liquid/i18n.rb +2 -2
  16. data/lib/liquid/interrupts.rb +1 -1
  17. data/lib/liquid/lexer.rb +11 -9
  18. data/lib/liquid/locales/en.yml +2 -4
  19. data/lib/liquid/parser.rb +2 -1
  20. data/lib/liquid/parser_switching.rb +31 -0
  21. data/lib/liquid/profiler.rb +162 -0
  22. data/lib/liquid/profiler/hooks.rb +23 -0
  23. data/lib/liquid/range_lookup.rb +22 -0
  24. data/lib/liquid/resource_limits.rb +23 -0
  25. data/lib/liquid/standardfilters.rb +142 -67
  26. data/lib/liquid/strainer.rb +14 -4
  27. data/lib/liquid/tag.rb +22 -41
  28. data/lib/liquid/tags/assign.rb +15 -10
  29. data/lib/liquid/tags/break.rb +1 -1
  30. data/lib/liquid/tags/capture.rb +7 -9
  31. data/lib/liquid/tags/case.rb +28 -19
  32. data/lib/liquid/tags/comment.rb +2 -2
  33. data/lib/liquid/tags/continue.rb +1 -4
  34. data/lib/liquid/tags/cycle.rb +10 -14
  35. data/lib/liquid/tags/decrement.rb +3 -4
  36. data/lib/liquid/tags/extends.rb +28 -44
  37. data/lib/liquid/tags/for.rb +64 -42
  38. data/lib/liquid/tags/if.rb +30 -19
  39. data/lib/liquid/tags/ifchanged.rb +4 -4
  40. data/lib/liquid/tags/include.rb +30 -20
  41. data/lib/liquid/tags/increment.rb +3 -8
  42. data/lib/liquid/tags/inherited_block.rb +54 -56
  43. data/lib/liquid/tags/raw.rb +18 -10
  44. data/lib/liquid/tags/table_row.rb +72 -0
  45. data/lib/liquid/tags/unless.rb +5 -7
  46. data/lib/liquid/template.rb +113 -53
  47. data/lib/liquid/token.rb +18 -0
  48. data/lib/liquid/utils.rb +13 -4
  49. data/lib/liquid/variable.rb +68 -50
  50. data/lib/liquid/variable_lookup.rb +78 -0
  51. data/lib/liquid/version.rb +1 -1
  52. data/test/fixtures/en_locale.yml +9 -0
  53. data/test/integration/assign_test.rb +48 -0
  54. data/test/integration/blank_test.rb +106 -0
  55. data/test/integration/capture_test.rb +50 -0
  56. data/test/integration/context_test.rb +32 -0
  57. data/test/integration/document_test.rb +19 -0
  58. data/test/integration/drop_test.rb +271 -0
  59. data/test/integration/error_handling_test.rb +207 -0
  60. data/test/integration/filter_test.rb +125 -0
  61. data/test/integration/hash_ordering_test.rb +23 -0
  62. data/test/integration/output_test.rb +116 -0
  63. data/test/integration/parsing_quirks_test.rb +119 -0
  64. data/test/integration/render_profiling_test.rb +154 -0
  65. data/test/integration/security_test.rb +64 -0
  66. data/test/integration/standard_filter_test.rb +379 -0
  67. data/test/integration/tags/break_tag_test.rb +16 -0
  68. data/test/integration/tags/continue_tag_test.rb +16 -0
  69. data/test/integration/tags/extends_tag_test.rb +104 -0
  70. data/test/integration/tags/for_tag_test.rb +375 -0
  71. data/test/integration/tags/if_else_tag_test.rb +169 -0
  72. data/test/integration/tags/include_tag_test.rb +234 -0
  73. data/test/integration/tags/increment_tag_test.rb +24 -0
  74. data/test/integration/tags/raw_tag_test.rb +25 -0
  75. data/test/integration/tags/standard_tag_test.rb +297 -0
  76. data/test/integration/tags/statements_test.rb +113 -0
  77. data/test/integration/tags/table_row_test.rb +63 -0
  78. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  79. data/test/integration/template_test.rb +216 -0
  80. data/test/integration/variable_test.rb +82 -0
  81. data/test/test_helper.rb +83 -0
  82. data/test/unit/block_unit_test.rb +55 -0
  83. data/test/unit/condition_unit_test.rb +149 -0
  84. data/test/unit/context_unit_test.rb +482 -0
  85. data/test/unit/file_system_unit_test.rb +35 -0
  86. data/test/unit/i18n_unit_test.rb +37 -0
  87. data/test/unit/lexer_unit_test.rb +51 -0
  88. data/test/unit/module_ex_unit_test.rb +87 -0
  89. data/test/unit/parser_unit_test.rb +82 -0
  90. data/test/unit/regexp_unit_test.rb +44 -0
  91. data/test/unit/strainer_unit_test.rb +71 -0
  92. data/test/unit/tag_unit_test.rb +16 -0
  93. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  94. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  95. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  96. data/test/unit/template_unit_test.rb +70 -0
  97. data/test/unit/tokenizer_unit_test.rb +38 -0
  98. data/test/unit/variable_unit_test.rb +150 -0
  99. metadata +144 -15
  100. data/lib/extras/liquid_view.rb +0 -51
  101. data/lib/liquid/htmltags.rb +0 -74
  102. data/lib/liquid/tags/default_content.rb +0 -21
  103. data/lib/locomotivecms-liquid.rb +0 -1
@@ -0,0 +1,125 @@
1
+ require 'test_helper'
2
+
3
+ module MoneyFilter
4
+ def money(input)
5
+ sprintf(' %d$ ', input)
6
+ end
7
+
8
+ def money_with_underscore(input)
9
+ sprintf(' %d$ ', input)
10
+ end
11
+ end
12
+
13
+ module CanadianMoneyFilter
14
+ def money(input)
15
+ sprintf(' %d$ CAD ', input)
16
+ end
17
+ end
18
+
19
+ module SubstituteFilter
20
+ def substitute(input, params={})
21
+ input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
22
+ end
23
+ end
24
+
25
+ class FiltersTest < Minitest::Test
26
+ include Liquid
27
+
28
+ def setup
29
+ @context = Context.new
30
+ end
31
+
32
+ def test_local_filter
33
+ @context['var'] = 1000
34
+ @context.add_filters(MoneyFilter)
35
+
36
+ assert_equal ' 1000$ ', Variable.new("var | money").render(@context)
37
+ end
38
+
39
+ def test_underscore_in_filter_name
40
+ @context['var'] = 1000
41
+ @context.add_filters(MoneyFilter)
42
+ assert_equal ' 1000$ ', Variable.new("var | money_with_underscore").render(@context)
43
+ end
44
+
45
+ def test_second_filter_overwrites_first
46
+ @context['var'] = 1000
47
+ @context.add_filters(MoneyFilter)
48
+ @context.add_filters(CanadianMoneyFilter)
49
+
50
+ assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context)
51
+ end
52
+
53
+ def test_size
54
+ @context['var'] = 'abcd'
55
+ @context.add_filters(MoneyFilter)
56
+
57
+ assert_equal 4, Variable.new("var | size").render(@context)
58
+ end
59
+
60
+ def test_join
61
+ @context['var'] = [1,2,3,4]
62
+
63
+ assert_equal "1 2 3 4", Variable.new("var | join").render(@context)
64
+ end
65
+
66
+ def test_sort
67
+ @context['value'] = 3
68
+ @context['numbers'] = [2,1,4,3]
69
+ @context['words'] = ['expected', 'as', 'alphabetic']
70
+ @context['arrays'] = ['flower', 'are']
71
+
72
+ assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
73
+ assert_equal ['alphabetic', 'as', 'expected'], Variable.new("words | sort").render(@context)
74
+ assert_equal [3], Variable.new("value | sort").render(@context)
75
+ assert_equal ['are', 'flower'], Variable.new("arrays | sort").render(@context)
76
+ end
77
+
78
+ def test_strip_html
79
+ @context['var'] = "<b>bla blub</a>"
80
+
81
+ assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
82
+ end
83
+
84
+ def test_strip_html_ignore_comments_with_html
85
+ @context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
86
+
87
+ assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
88
+ end
89
+
90
+ def test_capitalize
91
+ @context['var'] = "blub"
92
+
93
+ assert_equal "Blub", Variable.new("var | capitalize").render(@context)
94
+ end
95
+
96
+ def test_nonexistent_filter_is_ignored
97
+ @context['var'] = 1000
98
+
99
+ assert_equal 1000, Variable.new("var | xyzzy").render(@context)
100
+ end
101
+
102
+ def test_filter_with_keyword_arguments
103
+ @context['surname'] = 'john'
104
+ @context.add_filters(SubstituteFilter)
105
+ output = Variable.new(%! 'hello %{first_name}, %{last_name}' | substitute: first_name: surname, last_name: 'doe' !).render(@context)
106
+ assert_equal 'hello john, doe', output
107
+ end
108
+ end
109
+
110
+ class FiltersInTemplate < Minitest::Test
111
+ include Liquid
112
+
113
+ def test_local_global
114
+ with_global_filter(MoneyFilter) do
115
+ assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
116
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => CanadianMoneyFilter)
117
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => [CanadianMoneyFilter])
118
+ end
119
+ end
120
+
121
+ def test_local_filter_with_deprecated_syntax
122
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter)
123
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
124
+ end
125
+ end # FiltersTest
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ module MoneyFilter
4
+ def money(input)
5
+ sprintf(' %d$ ', input)
6
+ end
7
+ end
8
+
9
+ module CanadianMoneyFilter
10
+ def money(input)
11
+ sprintf(' %d$ CAD ', input)
12
+ end
13
+ end
14
+
15
+ class HashOrderingTest < Minitest::Test
16
+ include Liquid
17
+
18
+ def test_global_register_order
19
+ with_global_filter(MoneyFilter, CanadianMoneyFilter) do
20
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,116 @@
1
+ require 'test_helper'
2
+
3
+ module FunnyFilter
4
+ def make_funny(input)
5
+ 'LOL'
6
+ end
7
+
8
+ def cite_funny(input)
9
+ "LOL: #{input}"
10
+ end
11
+
12
+ def add_smiley(input, smiley = ":-)")
13
+ "#{input} #{smiley}"
14
+ end
15
+
16
+ def add_tag(input, tag = "p", id = "foo")
17
+ %|<#{tag} id="#{id}">#{input}</#{tag}>|
18
+ end
19
+
20
+ def paragraph(input)
21
+ "<p>#{input}</p>"
22
+ end
23
+
24
+ def link_to(name, url)
25
+ %|<a href="#{url}">#{name}</a>|
26
+ end
27
+
28
+ end
29
+
30
+ class OutputTest < Minitest::Test
31
+ include Liquid
32
+
33
+ def setup
34
+ @assigns = {
35
+ 'best_cars' => 'bmw',
36
+ 'car' => {'bmw' => 'good', 'gm' => 'bad'}
37
+ }
38
+ end
39
+
40
+ def test_variable
41
+ text = %| {{best_cars}} |
42
+
43
+ expected = %| bmw |
44
+ assert_equal expected, Template.parse(text).render!(@assigns)
45
+ end
46
+
47
+ def test_variable_traversing
48
+ text = %| {{car.bmw}} {{car.gm}} {{car.bmw}} |
49
+
50
+ expected = %| good bad good |
51
+ assert_equal expected, Template.parse(text).render!(@assigns)
52
+ end
53
+
54
+ def test_variable_piping
55
+ text = %( {{ car.gm | make_funny }} )
56
+ expected = %| LOL |
57
+
58
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
59
+ end
60
+
61
+ def test_variable_piping_with_input
62
+ text = %( {{ car.gm | cite_funny }} )
63
+ expected = %| LOL: bad |
64
+
65
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
66
+ end
67
+
68
+ def test_variable_piping_with_args
69
+ text = %! {{ car.gm | add_smiley : ':-(' }} !
70
+ expected = %| bad :-( |
71
+
72
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
73
+ end
74
+
75
+ def test_variable_piping_with_no_args
76
+ text = %! {{ car.gm | add_smiley }} !
77
+ expected = %| bad :-) |
78
+
79
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
80
+ end
81
+
82
+ def test_multiple_variable_piping_with_args
83
+ text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
84
+ expected = %| bad :-( :-( |
85
+
86
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
87
+ end
88
+
89
+ def test_variable_piping_with_multiple_args
90
+ text = %! {{ car.gm | add_tag : 'span', 'bar'}} !
91
+ expected = %| <span id="bar">bad</span> |
92
+
93
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
94
+ end
95
+
96
+ def test_variable_piping_with_variable_args
97
+ text = %! {{ car.gm | add_tag : 'span', car.bmw}} !
98
+ expected = %| <span id="good">bad</span> |
99
+
100
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
101
+ end
102
+
103
+ def test_multiple_pipings
104
+ text = %( {{ best_cars | cite_funny | paragraph }} )
105
+ expected = %| <p>LOL: bmw</p> |
106
+
107
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
108
+ end
109
+
110
+ def test_link_to
111
+ text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
112
+ expected = %| <a href="http://typo.leetsoft.com">Typo</a> |
113
+
114
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
115
+ end
116
+ end # OutputTest
@@ -0,0 +1,119 @@
1
+ require 'test_helper'
2
+
3
+ class ParsingQuirksTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_parsing_css
7
+ text = " div { font-weight: bold; } "
8
+ assert_equal text, Template.parse(text).render!
9
+ end
10
+
11
+ def test_raise_on_single_close_bracet
12
+ assert_raises(SyntaxError) do
13
+ Template.parse("text {{method} oh nos!")
14
+ end
15
+ end
16
+
17
+ def test_raise_on_label_and_no_close_bracets
18
+ assert_raises(SyntaxError) do
19
+ Template.parse("TEST {{ ")
20
+ end
21
+ end
22
+
23
+ def test_raise_on_label_and_no_close_bracets_percent
24
+ assert_raises(SyntaxError) do
25
+ Template.parse("TEST {% ")
26
+ end
27
+ end
28
+
29
+ def test_error_on_empty_filter
30
+ assert Template.parse("{{test}}")
31
+
32
+ with_error_mode(:lax) do
33
+ assert Template.parse("{{|test}}")
34
+ end
35
+
36
+ with_error_mode(:strict) do
37
+ assert_raises(SyntaxError) { Template.parse("{{|test}}") }
38
+ assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") }
39
+ end
40
+ end
41
+
42
+ def test_meaningless_parens_error
43
+ with_error_mode(:strict) do
44
+ assert_raises(SyntaxError) do
45
+ markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
46
+ Template.parse("{% if #{markup} %} YES {% endif %}")
47
+ end
48
+ end
49
+ end
50
+
51
+ def test_unexpected_characters_syntax_error
52
+ with_error_mode(:strict) do
53
+ assert_raises(SyntaxError) do
54
+ markup = "true && false"
55
+ Template.parse("{% if #{markup} %} YES {% endif %}")
56
+ end
57
+ assert_raises(SyntaxError) do
58
+ markup = "false || true"
59
+ Template.parse("{% if #{markup} %} YES {% endif %}")
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_no_error_on_lax_empty_filter
65
+ assert Template.parse("{{test |a|b|}}", :error_mode => :lax)
66
+ assert Template.parse("{{test}}", :error_mode => :lax)
67
+ assert Template.parse("{{|test|}}", :error_mode => :lax)
68
+ end
69
+
70
+ def test_meaningless_parens_lax
71
+ with_error_mode(:lax) do
72
+ assigns = {'b' => 'bar', 'c' => 'baz'}
73
+ markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
74
+ assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
75
+ end
76
+ end
77
+
78
+ def test_unexpected_characters_silently_eat_logic_lax
79
+ with_error_mode(:lax) do
80
+ markup = "true && false"
81
+ assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}")
82
+ markup = "false || true"
83
+ assert_template_result('',"{% if #{markup} %} YES {% endif %}")
84
+ end
85
+ end
86
+
87
+ def test_raise_on_invalid_tag_delimiter
88
+ assert_raises(Liquid::SyntaxError) do
89
+ Template.new.parse('{% end %}')
90
+ end
91
+ end
92
+
93
+ def test_unanchored_filter_arguments
94
+ with_error_mode(:lax) do
95
+ assert_template_result('hi',"{{ 'hi there' | split$$$:' ' | first }}")
96
+
97
+ assert_template_result('x', "{{ 'X' | downcase) }}")
98
+
99
+ # After the messed up quotes a filter without parameters (reverse) should work
100
+ # but one with parameters (remove) shouldn't be detected.
101
+ assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
102
+ assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
103
+ end
104
+ end
105
+
106
+ def test_invalid_variables_work
107
+ with_error_mode(:lax) do
108
+ assert_template_result('bar', "{% assign 123foo = 'bar' %}{{ 123foo }}")
109
+ assert_template_result('123', "{% assign 123 = 'bar' %}{{ 123 }}")
110
+ end
111
+ end
112
+
113
+ def test_extra_dots_in_ranges
114
+ with_error_mode(:lax) do
115
+ assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}")
116
+ end
117
+ end
118
+
119
+ end # ParsingQuirksTest
@@ -0,0 +1,154 @@
1
+ require 'test_helper'
2
+
3
+ class RenderProfilingTest < Minitest::Test
4
+ include Liquid
5
+
6
+ class ProfilingFileSystem
7
+ def read_template_file(template_path, context)
8
+ "Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
9
+ end
10
+ end
11
+
12
+ def setup
13
+ Liquid::Template.file_system = ProfilingFileSystem.new
14
+ end
15
+
16
+ def test_template_allows_flagging_profiling
17
+ t = Template.parse("{{ 'a string' | upcase }}")
18
+ t.render!
19
+
20
+ assert_nil t.profiler
21
+ end
22
+
23
+ def test_parse_makes_available_simple_profiling
24
+ t = Template.parse("{{ 'a string' | upcase }}", :profile => true)
25
+ t.render!
26
+
27
+ assert_equal 1, t.profiler.length
28
+
29
+ node = t.profiler[0]
30
+ assert_equal " 'a string' | upcase ", node.code
31
+ end
32
+
33
+ def test_render_ignores_raw_strings_when_profiling
34
+ t = Template.parse("This is raw string\nstuff\nNewline", :profile => true)
35
+ t.render!
36
+
37
+ assert_equal 0, t.profiler.length
38
+ end
39
+
40
+ def test_profiling_includes_line_numbers_of_liquid_nodes
41
+ t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :profile => true)
42
+ t.render!
43
+ assert_equal 2, t.profiler.length
44
+
45
+ # {{ 'a string' | upcase }}
46
+ assert_equal 1, t.profiler[0].line_number
47
+ # {{ increment test }}
48
+ assert_equal 2, t.profiler[1].line_number
49
+ end
50
+
51
+ def test_profiling_includes_line_numbers_of_included_partials
52
+ t = Template.parse("{% include 'a_template' %}", :profile => true)
53
+ t.render!
54
+
55
+ included_children = t.profiler[0].children
56
+
57
+ # {% assign template_name = 'a_template' %}
58
+ assert_equal 1, included_children[0].line_number
59
+ # {{ template_name }}
60
+ assert_equal 2, included_children[1].line_number
61
+ end
62
+
63
+ def test_profiling_times_the_rendering_of_tokens
64
+ t = Template.parse("{% include 'a_template' %}", :profile => true)
65
+ t.render!
66
+
67
+ node = t.profiler[0]
68
+ refute_nil node.render_time
69
+ end
70
+
71
+ def test_profiling_times_the_entire_render
72
+ t = Template.parse("{% include 'a_template' %}", :profile => true)
73
+ t.render!
74
+
75
+ assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
76
+ end
77
+
78
+ def test_profiling_uses_include_to_mark_children
79
+ t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :profile => true)
80
+ t.render!
81
+
82
+ include_node = t.profiler[1]
83
+ assert_equal 2, include_node.children.length
84
+ end
85
+
86
+ def test_profiling_marks_children_with_the_name_of_included_partial
87
+ t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :profile => true)
88
+ t.render!
89
+
90
+ include_node = t.profiler[1]
91
+ include_node.children.each do |child|
92
+ assert_equal "a_template", child.partial
93
+ end
94
+ end
95
+
96
+ def test_profiling_supports_multiple_templates
97
+ t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", :profile => true)
98
+ t.render!
99
+
100
+ a_template = t.profiler[1]
101
+ a_template.children.each do |child|
102
+ assert_equal "a_template", child.partial
103
+ end
104
+
105
+ b_template = t.profiler[2]
106
+ b_template.children.each do |child|
107
+ assert_equal "b_template", child.partial
108
+ end
109
+ end
110
+
111
+ def test_profiling_supports_rendering_the_same_partial_multiple_times
112
+ t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", :profile => true)
113
+ t.render!
114
+
115
+ a_template1 = t.profiler[1]
116
+ a_template1.children.each do |child|
117
+ assert_equal "a_template", child.partial
118
+ end
119
+
120
+ a_template2 = t.profiler[2]
121
+ a_template2.children.each do |child|
122
+ assert_equal "a_template", child.partial
123
+ end
124
+ end
125
+
126
+ def test_can_iterate_over_each_profiling_entry
127
+ t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :profile => true)
128
+ t.render!
129
+
130
+ timing_count = 0
131
+ t.profiler.each do |timing|
132
+ timing_count += 1
133
+ end
134
+
135
+ assert_equal 2, timing_count
136
+ end
137
+
138
+ def test_profiling_marks_children_of_if_blocks
139
+ t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", :profile => true)
140
+ t.render!
141
+
142
+ assert_equal 1, t.profiler.length
143
+ assert_equal 2, t.profiler[0].children.length
144
+ end
145
+
146
+ def test_profiling_marks_children_of_for_blocks
147
+ t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", :profile => true)
148
+ t.render!({"collection" => ["one", "two"]})
149
+
150
+ assert_equal 1, t.profiler.length
151
+ # Will profile each invocation of the for block
152
+ assert_equal 2, t.profiler[0].children.length
153
+ end
154
+ end