## ## $Release: 2.7.0 $ ## copyright(c) 2006-2011 kuwata-lab.com all rights reserved. ## require "#{File.dirname(__FILE__)}/test.rb" require 'stringio' require 'erubis' require 'erubis/engine/enhanced' require 'erubis/engine/optimized' require 'erubis/tiny' class ErubisTest < Test::Unit::TestCase testdata_list = load_yaml_datafile(__FILE__) define_testmethods(testdata_list) def _test() @src.gsub!(/\^/, ' ') @output.gsub!(/\^/, ' ') if @output.is_a?(String) if @class k = Erubis @class.split('::').each do |name| k = k.const_get(name) end @klass = k else @klass = Erubis::Eruby end @options ||= {} @chomp.each do |target| case target when 'src' ; @src.chomp! when 'input' ; @input.chomp! when 'expected' ; @expected.chomp! else raise "#{@name}: invalid chomp value: #{@chomp.inspect}" end end if @chomp if @testopt == 'load_file' filename = "tmp.#{@name}.eruby" begin File.open(filename, 'w') { |f| f.write(@input) } eruby = @klass.load_file(filename, @options) ensure cachename = filename + '.cache' File.unlink(cachename) if test(?f, cachename) File.unlink(filename) if test(?f, filename) end else if @klass == Erubis::TinyEruby eruby = @klass.new(@input) else eruby = @klass.new(@input, @options) end end assert_text_equal(@src, eruby.src) return if @testopt == 'skip_output' list = ['', 'b&b', '"ccc"'] context = @testopt == 'context' ? Erubis::Context.new : {} context[:list] = list case @testopt when /\Aeval\(/ eval eruby.src actual = eval @testopt assert_text_equal(@output, actual) when 'stdout', 'print' begin orig = $stdout $stdout = stringio = StringIO.new #actual = eruby.evaluate(context) actual = eruby.result(context) ensure $stdout = orig end if @testopt == 'stdout' assert_equal("", actual) else assert_nil(actual) end assert_text_equal(@output, stringio.string) when 'evaluate', 'context' actual = eruby.evaluate(context) assert_text_equal(@output, actual) when 'binding' actual = eruby.result(binding()) assert_text_equal(@output, actual) else actual = eruby.result(context) assert_text_equal(@output, actual) end end def test_load_file_cache1 @input = < <% for item in @list %>
  • <%= item %>
  • <% end %> END @src = < '; for item in @list _buf << '
  • '; _buf << ( item ).to_s; _buf << '
  • '; end _buf << ' '; _buf.to_s END @klass = Erubis::Eruby filename = 'tmp.load_file_timestamp1' cachename = filename + '.cache' begin ## when cache doesn't exist then it is created automatically File.open(filename, 'w') { |f| f.write(@input) } mtime = Time.now - 2.0 File.utime(mtime, mtime, filename) !test(?f, cachename) or raise "** failed" engine = @klass.load_file(filename) assert_block() { test(?f, cachename) } assert_block() { File.mtime(filename) <= File.mtime(cachename) } assert_text_equal(@src, engine.src) ## when cache has different timestamp then it is recreated input2 = @input.gsub(/ul>/, 'ol>') src2 = @src.gsub(/ul>/, 'ol>') File.open(filename, 'w') { |f| f.write(input2) } t1 = Time.now() sleep(1) t2 = Time.now() # File.utime(t1, t1, filename) File.utime(t2, t2, cachename) File.mtime(filename) < File.mtime(cachename) or raise "** failed" engine = @klass.load_file(filename) assert_block('cache should have same timestamp') { File.mtime(filename) == File.mtime(cachename) } #assert_text_equal(@src, engine.src) assert_text_equal(src2, engine.src) # File.utime(t2, t2, filename) File.utime(t1, t1, cachename) File.mtime(filename) > File.mtime(cachename) or raise "** failed" engine = @klass.load_file(filename) assert_block('cache should have same timestamp') { File.mtime(filename) == File.mtime(cachename) } assert_text_equal(src2, engine.src) ensure File.unlink(cachename) if File.file?(cachename) File.unlink(filename) if File.file?(filename) end end class Dummy end def _class_has_instance_method(klass, method) return klass.instance_methods.collect{|m| m.to_s}.include?(method.to_s) end def test_def_method1 s = "<%for i in list%>i=<%=i%>\n<%end%>" eruby = Erubis::Eruby.new(s) assert(! _class_has_instance_method(Dummy, 'render')) eruby.def_method(Dummy, 'render(list)', 'foo.rhtml') assert(_class_has_instance_method(Dummy, 'render')) actual = Dummy.new().render(%w[1 2 3]) assert_equal("i=1\ni=2\ni=3\n", actual) end def test_def_method2 s = "<%for i in list%>i=<%=i%>\n<%end%>" eruby = Erubis::Eruby.new(s) assert(! (eruby.respond_to? :render)) eruby.def_method(eruby, 'render(list)', 'foo.rhtml') assert eruby.respond_to?(:render) actual = eruby.render([1, 2, 3]) assert_equal("i=1\ni=2\ni=3\n", actual) assert(! _class_has_instance_method(eruby.class, 'render')) end def test_evaluate_creates_proc s = "hello <%= @name %>" eruby = Erubis::Eruby.new(s) assert_nil(eruby.instance_variable_get('@_proc')) actual1 = eruby.evaluate(:name=>'world') assert_not_nil(eruby.instance_variable_get('@_proc')) assert_instance_of(Proc, eruby.instance_variable_get('@_proc')) actual2 = eruby.evaluate(:name=>'world') assert_equal(actual1, actual2) # convert() must clear @_proc eruby.convert(s) assert_nil(eruby.instance_variable_get('@_proc')) end #def test_toplevel_binding # s = "locals = <%= local_variables().inspect %>\n<% x = 50 %>\n" # eruby = Erubis::Eruby.new(s) # _x = eval 'x', TOPLEVEL_BINDING # _y = eval 'y', TOPLEVEL_BINDING # actual = eruby.evaluate(:x=>_x, :y=>_y) # _x = eval 'x', TOPLEVEL_BINDING # _y = eval 'y', TOPLEVEL_BINDING # puts "*** actual=#{actual.inspect}, x=#{_x.inspect}, y=#{_y.inspect}" #end self.post_definition() end x = 10 y = 20 __END__ - name: basic1 input: &basic1_input|
      <% for item in list %>
    • <%= item %>
    • <% end %>
    src: &basic1_src| _buf = ''; _buf << '
      '; for item in list _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: &basic1_output|
    • b&b
    • "ccc"
    ## - name: basic2 input: |
      <% i = 0 for item in list i += 1 %>
    • <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; i = 0 for item in list i += 1 ^^^ _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: *basic1_output #
      #
    • #
    • b&b
    • #
    • "ccc"
    • #
    ## - name: basic3 input: |
      <% i = 0 for item in list i += 1 %>
    • <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; i = 0 for item in list i += 1 ; _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end ; _buf << ' '; _buf << '
    '; _buf.to_s output: |
    • b&b
    • "ccc"
    ## - name: context1 testopt: context input: |
      <% for item in @list %>
    • <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; for item in @list _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: *basic1_output ## - name: ignore1 input: |
      <%# i = 0 %> <% for item in list %> <%# i += 1 color = i % 2 == 0 ? '#FFCCCC' : '#CCCCFF' %>
    • <%#= i %> : <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; for item in list _buf << '
    • ';; _buf << ' : '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: |
    • :
    • : b&b
    • : "ccc"
    ## - name: quotation1 desc: single quotation and backslash class: Eruby input: "ation1_input| a = "'" b = "\"" c = '\'' src: | _buf = ''; _buf << 'a = "\'" b = "\\"" c = \'\\\'\' '; _buf.to_s output: *quotation1_input ## - name: minus1 desc: '<%- -%>' class: Eruby input: |
      <%- for item in list -%>
    • <%= item -%>
    • <% end -%>
    src: *basic1_src output: *basic1_output ## - name: pattern1 options: :pattern : '\[@ @\]' input: |
      [@ for item in list @]
    • [@= item @]
    • [@ end @]
    src: | _buf = ''; _buf << '
      '; for item in list _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: *basic1_output #
      #
    • #
    • b&b
    • #
    • "ccc"
    • #
    ## - name: pattern2 options: :pattern : '<(?:!--)?% %(?:--)?>' input: |
    • <%= item %>
    src: | _buf = ''; _buf << '
      '; for item in list _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: *basic1_output #
      #
    • #
    • b&b
    • #
    • "ccc"
    • #
    ## - name: trim1 options: :trim : false input: *basic1_input #
      # <% for item in list %> #
    • <%= item %>
    • # <% end %> #
    src: | _buf = ''; _buf << '
      '; _buf << ' '; for item in list ; _buf << ' '; _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; _buf << ' '; end ; _buf << ' '; _buf << '
    '; _buf.to_s output: |
      ^
    • ^
    • b&b
    • ^
    • "ccc"
    • ^
    ## - name: bodyonly1 testopt: skip_output options: { :preamble: no, :postamble: no } input: *basic1_input src: |4 _buf << '
      '; for item in list _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; chomp: [src] expected: null ## - name: loadfile1 testopt: load_file #input: | #
      # <% for item in list %> #
    • <%= item %>
    • # <% end %> #
    input: "
      \r\n <% for item in list %>\r\n
    • <%= item %>
    • \r\n <% end %>\r\n
    \r\n" #src: | # _buf = ''; _buf << "
      \n" # for item in list # _buf << "
    • "; _buf << ( item ).to_s; _buf << "
    • \n" # end # _buf << "
    \n" # _buf src: "_buf = ''; _buf << '
      \r\n'; for item in list \r\n _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • \r\n'; end \r\n _buf << '
    \r\n';\n_buf.to_s\n" #output: | #
      #
    • #
    • b&b
    • #
    • "ccc"
    • #
    output: "
      \n
    • \n
    • b&b
    • \n
    • \"ccc\"
    • \n
    \n" # "
      \r\n
    • \r\n
    • b&b
    • \r\n
    • \"ccc\"
    • \r\n
    \r\n" ## - name: nomatch1 desc: bug input: &nomatch1|
    • foo
    src: | _buf = ''; _buf << '
    • foo
    '; _buf.to_s output: *nomatch1 ## - name: escape1 options: { :escape: true } input: | <% str = '<>&"' %> <%= str %> <%== str %> src: | _buf = ''; str = '<>&"' _buf << Erubis::XmlHelper.escape_xml( str ); _buf << ' '; _buf << ( str ).to_s; _buf << ' '; _buf.to_s output: | <>&" <>&" ## - name: tailch1 options: input: |

    <% str = '<>&"' %> <%= str %> <%= str =%> <%= str -%>

    src: | _buf = ''; _buf << '

    '; str = '<>&"' _buf << ' '; _buf << ( str ).to_s; _buf << ' '; _buf << ' '; _buf << ( str ).to_s; _buf << ' '; _buf << ( str ).to_s; _buf << '

    '; _buf.to_s output: |

    <>&" <>&" <>&"

    ## - name: doublepercent1 options: input: | <% x1 = 10 %> <%% x2 = 20 %> <%= x1 %> <%%= x2 %> src: | _buf = ''; x1 = 10 _buf << '<% x2 = 20 %> '; _buf << ( x1 ).to_s; _buf << ' '; _buf << '<%= x2 %> '; _buf.to_s output: | <% x2 = 20 %> 10 <%= x2 %> ## - name: optimized1 class: OptimizedEruby input: &optimized1_input| <% for item in list %> <% end %>
    <%= item %> <%== item %>
      <% for item in list %>
    • <%= item %>
    • <% end %>
    src: | _buf = ' '; for item in list _buf << ' '; end _buf << '
    ' << ( item ).to_s << ' ' << Erubis::XmlHelper.escape_xml( item ) << '
      '; for item in list ; _buf << '
    • ' << ( item ).to_s << '
    • '; end ; _buf << '
    ' _buf output: |
    <aaa>
    b&b b&b
    "ccc" "ccc"
    • b&b
    • "ccc"
    ## - name: optimized2 class: OptimizedXmlEruby input: *optimized1_input # # <% for item in list %> # # # # # <% end %> #
    <%= item %><%== item %>
    #
      <% for item in list %>
    • <%= item %>
    • <% end %>
    src: | _buf = ' '; for item in list _buf << ' '; end _buf << '
    ' << Erubis::XmlHelper.escape_xml( item ) << ' ' << ( item ).to_s << '
      '; for item in list ; _buf << '
    • ' << Erubis::XmlHelper.escape_xml( item ) << '
    • '; end ; _buf << '
    ' _buf output: |
    <aaa>
    b&b b&b
    "ccc" "ccc"
    • <aaa>
    • b&b
    • "ccc"
    ## - name: optimized3 desc: bug class: OptimizedEruby input: | user = <%= "Foo" %> <% for item in list %> <%= item %> <% end %> src: | _buf = 'user = '; _buf << ( "Foo" ).to_s << ' '; for item in list _buf << ' ' << ( item ).to_s << ' '; end _buf output: | user = Foo b&b "ccc" ## - name: optimized4 desc: single quotation and backslash class: OptimizedEruby input: &optimized4_input| a = "'" b = "\"" c = '\'' src: | _buf = 'a = "\'" b = "\\"" c = \'\\\'\' '; _buf output: *optimized4_input ## - name: tiny1 class: TinyEruby testopt: binding input: |
      <% for item in list %>
    • <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; for item in list ; _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end ; _buf << '
    '; _buf.to_s output: |
      ^
    • ^
    • b&b
    • ^
    • "ccc"
    • ^
    ## - name: tiny2 class: TinyEruby testopt: evaluate input: |
      <% for item in @list %>
    • <%= item %>
    • <% end %>
    src: | _buf = ''; _buf << '
      '; for item in @list ; _buf << '
    • '; _buf << ( item ).to_s; _buf << '
    • '; end ; _buf << '
    '; _buf.to_s output: |
      ^
    • ^
    • b&b
    • ^
    • "ccc"
    • ^
    ## - name: pi1 class: PI::Eruby testopt: evaluate input: &input_pi1|
    • @{item}@ / @!{item}@
    • <%= item %> / <%== item %>
    src: &src_pi1| _buf = ''; _buf << '
      '; for item in @list _buf << '
    • '; _buf << Erubis::XmlHelper.escape_xml(item); _buf << ' / '; _buf << (item).to_s; _buf << '
    • '; _buf << ( item ).to_s; _buf << ' / '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '
    • '; end _buf << '
    '; _buf.to_s output: &output_pi1|
    • <aaa> /
    • / <aaa>
    • b&b / b&b
    • b&b / b&b
    • "ccc" / "ccc"
    • "ccc" / "ccc"
    ## - name: pi2 class: PI::Eruby options: { :escape: false } testopt: evaluate input: *input_pi1 src: | _buf = ''; _buf << '
      '; for item in @list _buf << '
    • '; _buf << (item).to_s; _buf << ' / '; _buf << Erubis::XmlHelper.escape_xml(item); _buf << '
    • '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << ' / '; _buf << ( item ).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: |
    • / <aaa>
    • <aaa> /
    • b&b / b&b
    • b&b / b&b
    • "ccc" / "ccc"
    • "ccc" / "ccc"
    ## - name: pi3 class: PI::Eruby options: { :pi: hoge, :embchar: '$' } testopt: evaluate input: |
    • ${item}$ / $!{item}$
    • <%= item %> / <%== item %>
    src: *src_pi1 output: *output_pi1 - name: pi4 class: PI::Eruby testopt: evaluate input: |
    src: |4 def show(list) _buf = ''; _buf << '
      '; for item in list _buf << ( item ).to_s; end _buf << '
    '; _buf.to_s end show(@list) output: |
      b&b"ccc"
    - name: pitiny1 class: PI::TinyEruby testopt: evaluate input: |
    • @{item}@ / @!{item}@
    src: | _buf = ''; _buf << '
      '; for item in @list _buf << '
    • '; _buf << Erubis::XmlHelper.escape_xml(item); _buf << ' / '; _buf << (item).to_s; _buf << '
    • '; end _buf << '
    '; _buf.to_s output: |
    • <aaa> /
    • b&b / b&b
    • "ccc" / "ccc"