aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/template/compiled_templates_test.rb
blob: b969575235f59d1ed883ecef8336bf73fb971fe4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
require 'abstract_unit'
require 'action_view/helpers/date_helper'
require 'action_view/compiled_templates'

class CompiledTemplateTests < Test::Unit::TestCase
  def setup
    @ct = ActionView::CompiledTemplates.new
    @v = Class.new
    @v.send :include, @ct
    @a = './test_compile_template_a.rhtml'
    @b = './test_compile_template_b.rhtml'
    @s = './test_compile_template_link.rhtml'
  end
  def teardown
    [@a, @b, @s].each do |f|
      FileUtils.rm(f) if File.exist?(f) || File.symlink?(f)
    end
  end
  attr_reader :ct, :v

  def test_name_allocation
    hi_world = ct.method_names['hi world']
    hi_sexy = ct.method_names['hi sexy']
    wish_upon_a_star = ct.method_names['I love seeing decent error messages']

    assert_equal hi_world, ct.method_names['hi world']
    assert_equal hi_sexy, ct.method_names['hi sexy']
    assert_equal wish_upon_a_star, ct.method_names['I love seeing decent error messages']
    assert_equal 3, [hi_world, hi_sexy, wish_upon_a_star].uniq.length
  end

  def test_wrap_source
    assert_equal(
      "def aliased_assignment(value)\nself.value = value\nend",
      @ct.wrap_source(:aliased_assignment, [:value], 'self.value = value')
    )

    assert_equal(
      "def simple()\nnil\nend",
      @ct.wrap_source(:simple, [], 'nil')
    )
  end

  def test_compile_source_single_method
    selector = ct.compile_source('doubling method', [:a], 'a + a')
    assert_equal 2, @v.new.send(selector, 1)
    assert_equal 4, @v.new.send(selector, 2)
    assert_equal -4, @v.new.send(selector, -2)
    assert_equal 0, @v.new.send(selector, 0)
    selector
  end

  def test_compile_source_two_method
    sel1 = test_compile_source_single_method # compile the method in the other test
    sel2 = ct.compile_source('doubling method', [:a, :b], 'a + b + a + b')
    assert_not_equal sel1, sel2

    assert_equal 2, @v.new.send(sel1, 1)
    assert_equal 4, @v.new.send(sel1, 2)

    assert_equal 6, @v.new.send(sel2, 1, 2)
    assert_equal 32, @v.new.send(sel2, 15, 1)
  end

  def test_mtime
    t1 = Time.now

    test_compile_source_single_method
    mtime = ct.mtime('doubling method', [:a])

    assert mtime < Time.now
    assert mtime > t1
  end

  uses_mocha 'test_compile_time' do

    def test_compile_time
      t = Time.now

      File.open(@a, "w"){|f| f.puts @a}
      File.open(@b, "w"){|f| f.puts @b}
      # windows doesn't support symlinks (even under cygwin)
      windows = (RUBY_PLATFORM =~ /win32/)
      `ln -s #{@a} #{@s}` unless windows

      v = ActionView::Base.new
      v.base_path = '.'
      v.cache_template_loading = false

      ta = ActionView::Template.new(v, @a, false, {})
      tb = ActionView::Template.new(v, @b, false, {})
      ts = ActionView::Template.new(v, @s, false, {})

      @handler_class = ActionView::Base.handler_class_for_extension(:rhtml)
      @handler       = @handler_class.new(v)

      # All templates were created at t+1
      File::Stat.any_instance.expects(:mtime).times(windows ? 2 : 3).returns(t + 1.second)

      # private methods template_changed_since? and compile_template?
      # should report true for all since they have not been compiled
      assert @handler.send(:template_changed_since?, @a, t)
      assert @handler.send(:template_changed_since?, @b, t)
      assert @handler.send(:template_changed_since?, @s, t) unless windows

      assert @handler.send(:compile_template?, ta)
      assert @handler.send(:compile_template?, tb)
      assert @handler.send(:compile_template?, ts) unless windows

      # All templates are rendered at t+2
      Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds)
      v.send(:render_template, ta)
      v.send(:render_template, tb)
      v.send(:render_template, ts) unless windows
      a_n = v.method_names[@a]
      b_n = v.method_names[@b]
      s_n = v.method_names[@s] unless windows
      # all of the files have changed since last compile
      assert @handler.compile_time[a_n] > t
      assert @handler.compile_time[b_n] > t
      assert @handler.compile_time[s_n] > t unless windows

      # private methods template_changed_since? and compile_template?
      # should report false for all since none have changed since compile
      File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns(t + 1.second)
      assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n])
      assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n])
      assert !@handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows
      assert !@handler.send(:compile_template?, ta)
      assert !@handler.send(:compile_template?, tb)
      assert !@handler.send(:compile_template?, ts) unless windows
      v.send(:render_template, ta)
      v.send(:render_template, tb)
      v.send(:render_template, ts)  unless windows
      # none of the files have changed since last compile
      assert @handler.compile_time[a_n] < t + 3.seconds
      assert @handler.compile_time[b_n] < t + 3.seconds
      assert @handler.compile_time[s_n] < t + 3.seconds  unless windows

      `rm #{@s}; ln -s #{@b} #{@s}` unless windows
      # private methods template_changed_since? and compile_template?
      # should report true for symlink since it has changed since compile
    
      # t + 3.seconds is for the symlink
      File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 9).returns(
        *(windows ? [ t + 1.second, t + 1.second ] :
          [ t + 1.second, t + 1.second, t + 3.second ]) * 3)
      assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n])
      assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n])
      assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows
      assert !@handler.send(:compile_template?, ta)
      assert !@handler.send(:compile_template?, tb)
      assert @handler.send(:compile_template?, ts) unless windows

      # Only the symlink template gets rendered at t+3
      Time.stubs(:now).returns(t + 3.seconds) unless windows
      v.send(:render_template, ta)
      v.send(:render_template, tb)
      v.send(:render_template, ts) unless windows
      # the symlink has changed since last compile
      assert @handler.compile_time[a_n] < t + 3.seconds
      assert @handler.compile_time[b_n] < t + 3.seconds
      assert_equal @handler.compile_time[s_n], t + 3.seconds unless windows

      FileUtils.touch @b
      # private methods template_changed_since? and compile_template?
      # should report true for symlink and file at end of symlink
      # since it has changed since last compile
      #
      # t+4 is for @b and also for the file that @s points to, which is @b
      File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns(
        *(windows ? [ t + 1.second, t + 4.seconds ] :
          [ t + 1.second, t + 4.seconds, t + 3.second, t + 4.seconds ]) * 3)
      assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n])
      assert @handler.send(:template_changed_since?, @b, @handler.compile_time[b_n])
      assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows
      assert !@handler.send(:compile_template?, ta)
      assert @handler.send(:compile_template?, tb)
      assert @handler.send(:compile_template?, ts) unless windows

      Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds)
      v.send(:render_template, ta)
      v.send(:render_template, tb)
      v.send(:render_template, ts) unless windows
      # the file at the end of the symlink has changed since last compile
      # both the symlink and the file at the end of it should be recompiled
      assert @handler.compile_time[a_n] < t + 5.seconds
      assert_equal @handler.compile_time[b_n], t + 5.seconds
      assert_equal @handler.compile_time[s_n], t + 5.seconds unless windows
    end
  end
end