1 # -*- coding: us-ascii -*-
2 # frozen_string_literal: false
7 class TestERB < Test::Unit::TestCase
8 class MyError < RuntimeError ; end
10 def test_without_filename
11 erb = ERB.new("<% raise ::TestERB::MyError %>")
12 e = assert_raise(MyError) {
15 assert_match(/\A\(erb\):1\b/, e.backtrace[0])
18 def test_with_filename
19 erb = ERB.new("<% raise ::TestERB::MyError %>")
20 erb.filename = "test filename"
21 e = assert_raise(MyError) {
24 assert_match(/\Atest filename:1\b/, e.backtrace[0])
27 # [deprecated] This will be removed later
28 def test_without_filename_with_safe_level
29 erb = EnvUtil.suppress_warning do
30 ERB.new("<% raise ::TestERB::MyError %>", 1)
32 e = assert_raise(MyError) {
35 assert_match(/\A\(erb\):1\b/, e.backtrace[0])
38 # [deprecated] This will be removed later
39 def test_with_filename_and_safe_level
40 erb = EnvUtil.suppress_warning do
41 ERB.new("<% raise ::TestERB::MyError %>", 1)
43 erb.filename = "test filename"
44 e = assert_raise(MyError) {
47 assert_match(/\Atest filename:1\b/, e.backtrace[0])
50 def test_with_filename_lineno
51 erb = ERB.new("<% raise ::TestERB::MyError %>")
52 erb.filename = "test filename"
54 e = assert_raise(MyError) {
57 assert_match(/\Atest filename:101\b/, e.backtrace[0])
60 def test_with_location
61 erb = ERB.new("<% raise ::TestERB::MyError %>")
62 erb.location = ["test filename", 200]
63 e = assert_raise(MyError) {
66 assert_match(/\Atest filename:201\b/, e.backtrace[0])
70 assert_equal(" !"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
71 ERB::Util.html_escape(" !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"))
73 assert_equal("", ERB::Util.html_escape(""))
74 assert_equal("abc", ERB::Util.html_escape("abc"))
75 assert_equal("<<", ERB::Util.html_escape("<\<"))
77 assert_equal("", ERB::Util.html_escape(nil))
78 assert_equal("123", ERB::Util.html_escape(123))
81 def test_concurrent_default_binding
82 template1 = 'one <%= ERB.new(template2).result %>'
84 eval 'template2 = "two"', TOPLEVEL_BINDING
86 bug7046 = '[ruby-core:47638]'
87 assert_equal("one two", ERB.new(template1).result, bug7046)
91 class TestERBCore < Test::Unit::TestCase
97 assert_equal(String, @erb.version.class)
101 # [deprecated] Fix initializer later
102 EnvUtil.suppress_warning do
110 erb = @erb.new("hello")
111 assert_equal("hello", erb.result)
113 erb = @erb.new("hello", safe, 0)
114 assert_equal("hello", erb.result)
116 erb = @erb.new("hello", safe, 1)
117 assert_equal("hello", erb.result)
119 erb = @erb.new("hello", safe, 2)
120 assert_equal("hello", erb.result)
146 assert_equal(ans, erb.result)
147 erb = @erb.new(src, safe, 0)
148 assert_equal(ans, erb.result)
149 erb = @erb.new(src, safe, '')
150 assert_equal(ans, erb.result)
160 erb = @erb.new(src, safe, 1)
161 assert_equal(ans.chomp, erb.result)
162 erb = @erb.new(src, safe, '>')
163 assert_equal(ans.chomp, erb.result)
176 erb = @erb.new(src, safe, 2)
177 assert_equal(ans, erb.result)
178 erb = @erb.new(src, safe, '<>')
179 assert_equal(ans, erb.result)
192 erb = @erb.new(src, safe, '%')
193 assert_equal(ans, erb.result)
200 erb = @erb.new(src, safe, '%>')
201 assert_equal(ans.chomp, erb.result)
210 erb = @erb.new(src, safe, '%<>')
211 assert_equal(ans, erb.result)
214 def test_trim_line1_with_carriage_return
215 erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '>')
216 assert_equal("line\r\n" * 3, erb.result)
218 erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '%>')
219 assert_equal("line\r\n" * 3, erb.result)
222 def test_trim_line2_with_carriage_return
223 erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '<>')
224 assert_equal("line\r\n" * 3, erb.result)
226 erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '%<>')
227 assert_equal("line\r\n" * 3, erb.result)
230 def test_explicit_trim_line_with_carriage_return
231 erb = @erb.new("<%- 3.times do -%>\r\nline\r\n<%- end -%>\r\n", trim_mode: '-')
232 assert_equal("line\r\n" * 3, erb.result)
234 erb = @erb.new("<%- 3.times do -%>\r\nline\r\n<%- end -%>\r\n", trim_mode: '%-')
235 assert_equal("line\r\n" * 3, erb.result)
238 def test_invalid_trim_mode
239 assert_warning(/#{__FILE__}:#{__LINE__ + 1}/) do
240 @erb.new("", trim_mode: 'abc-def')
243 assert_warning(/Invalid ERB trim mode/) do
244 @erb.new("", trim_mode: 'abc-def')
247 assert_warning(/Invalid ERB trim mode/) do
248 @erb.new("", trim_mode: '%<')
251 assert_warning(/Invalid ERB trim mode/) do
252 @erb.new("", trim_mode: '%<>-')
255 assert_warning(/Invalid ERB trim mode/) do
256 @erb.new("", trim_mode: 3)
262 orig, $stdout = $stdout, out
265 @erb.new('<%= num * 3 %>').run(binding)
269 assert_equal('9', out.read)
270 return unless num # to remove warning
276 erb = @erb.new('hello')
278 assert_equal(Object, cls.superclass)
279 assert_respond_to(cls.new, 'result')
280 cls = erb.def_class(Foo)
281 assert_equal(Foo, cls.superclass)
282 assert_respond_to(cls.new, 'result')
283 cls = erb.def_class(Object, 'erb')
284 assert_equal(Object, cls.superclass)
285 assert_respond_to(cls.new, 'erb')
293 assert_equal("1\n", ERB.new(src, trim_mode: '%').result(binding))
300 assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
305 assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
312 assert_equal("1\n", ERB.new(src, trim_mode: '%').result(binding))
328 assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
331 def test_def_erb_method
334 extend ERB::DefMethod
335 fname = File.join(File.dirname(File.expand_path(__FILE__)), 'hello.erb')
336 def_erb_method('hello', fname)
338 assert_respond_to(klass.new, 'hello')
340 assert_not_respond_to(klass.new, 'hello_world')
341 erb = @erb.new('hello, world')
343 def_erb_method('hello_world', erb)
345 assert_respond_to(klass.new, 'hello_world')
348 def test_def_method_without_filename
350 erb = ERB.new("<% raise ::TestERB::MyError %>")
351 erb.filename = "test filename"
352 assert_not_respond_to(klass.new, 'my_error')
353 erb.def_method(klass, 'my_error')
354 e = assert_raise(::TestERB::MyError) {
357 assert_match(/\A\(ERB\):1\b/, e.backtrace[0])
360 def test_def_method_with_fname
362 erb = ERB.new("<% raise ::TestERB::MyError %>")
363 erb.filename = "test filename"
364 assert_not_respond_to(klass.new, 'my_error')
365 erb.def_method(klass, 'my_error', 'test fname')
366 e = assert_raise(::TestERB::MyError) {
369 assert_match(/\Atest fname:1\b/, e.backtrace[0])
374 klass.include ERB.new('<%= val %>').def_module('render(val)')
375 assert_equal('1', klass.new.render(1))
412 assert_equal(ans, ERB.new(src, trim_mode: '%').result)
423 erb = ERB.new(src, trim_mode: '%')
424 e = assert_raise(RuntimeError) {
427 assert_match(/\A\(erb\):4\b/, e.backtrace[0].to_s)
441 assert_equal(ans, ERB.new(src, trim_mode: '>').result)
449 assert_equal(ans, ERB.new(src, trim_mode: '<>').result)
458 assert_equal(ans, ERB.new(src).result)
465 <% raise("lineno") %>
469 e = assert_raise(RuntimeError) {
472 assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
474 erb = ERB.new(src, trim_mode: '>')
475 e = assert_raise(RuntimeError) {
478 assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
480 erb = ERB.new(src, trim_mode: '<>')
481 e = assert_raise(RuntimeError) {
484 assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
490 <%= x %><%- x = nil -%>\s
491 <% raise("lineno") %>
494 erb = ERB.new(src, trim_mode: '-')
495 e = assert_raise(RuntimeError) {
498 assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
500 erb = ERB.new(src, trim_mode: '%-')
501 e = assert_raise(RuntimeError) {
504 assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
509 <% x = %w(hello world) -%>
510 NotSkip <%- y = x -%> NotSkip
512 <%- up = w.upcase -%>
515 <%- z = nil -%> NotSkip <%- z = x %>
516 <%- z.each do |w| -%>
517 <%- down = w.downcase -%>
519 <%- up = w.upcase -%>
522 KeepNewLine <%- z = nil -%>\s
536 assert_equal(ans, ERB.new(src, trim_mode: '-').result)
537 assert_equal(ans, ERB.new(src, trim_mode: '-%').result)
541 assert_equal("Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide",
542 ERB::Util.url_encode("Programming Ruby: The Pragmatic Programmer's Guide"))
544 assert_equal("%A5%B5%A5%F3%A5%D7%A5%EB",
545 ERB::Util.url_encode("\xA5\xB5\xA5\xF3\xA5\xD7\xA5\xEB".force_encoding("EUC-JP")))
547 assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
548 ERB::Util.url_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
549 "should not escape any unreserved characters, as per RFC3986 Section 2.3")
552 def test_percent_after_etag
553 assert_equal("1%", @erb.new("<%= 1 %>%", trim_mode: "%").result)
556 def test_token_extension
557 extended_erb = Class.new(ERB)
558 extended_erb.module_eval do
559 def make_compiler(trim_mode)
560 compiler = Class.new(ERB::Compiler)
561 compiler.module_eval do
562 def compile_stag(stag, out, scanner)
566 add_put_cmd(out, content) if content.size > 0
573 def compile_content(stag, out)
576 out.push("#{@insert_cmd}(::ERB::Util.html_escape(#{content}))")
582 def make_scanner(src)
583 scanner = Class.new(ERB::Compiler::SimpleScanner)
584 scanner.module_eval do
589 scanner.new(src, @trim_mode, @percent)
592 compiler.new(trim_mode)
606 assert_equal(ans, extended_erb.new(src).result)
609 def test_frozen_string_literal
610 bug12031 = '[ruby-core:73561] [Bug #12031]'
611 e = @erb.new("<%#encoding: us-ascii%>a")
612 e.src.sub!(/\A#(?:-\*-)?(.*)(?:-\*-)?/) {
613 '# -*- \1; frozen-string-literal: true -*-'
615 assert_equal("a", e.result, bug12031)
617 %w(false true).each do |flag|
618 erb = @erb.new("<%#frozen-string-literal: #{flag}%><%=''.frozen?%>")
619 assert_equal(flag, erb.result)
623 def test_result_with_hash
624 erb = @erb.new("<%= foo %>")
625 assert_equal("1", erb.result_with_hash(foo: "1"))
628 def test_result_with_hash_does_not_use_caller_local_variables
629 erb = @erb.new("<%= foo %>")
631 assert_raise(NameError) { erb.result_with_hash({}) }
632 assert_equal("1", erb.result_with_hash(foo: foo))
635 def test_result_with_hash_does_not_modify_caller_binding
636 erb = @erb.new("<%= foo %>")
637 erb.result_with_hash(foo: "1")
638 assert_equal(false, binding.local_variable_defined?(:foo))
641 def test_result_with_hash_does_not_modify_toplevel_binding
642 erb = @erb.new("<%= foo %>")
643 erb.result_with_hash(foo: "1")
644 assert_equal(false, TOPLEVEL_BINDING.local_variable_defined?(:foo))
645 TOPLEVEL_BINDING.eval 'template2 = "two"'
646 erb = @erb.new("<%= template2 %>")
647 erb.result_with_hash(template2: "TWO")
648 assert_equal "two", TOPLEVEL_BINDING.local_variable_get("template2")
651 # This depends on the behavior that #local_variable_set raises TypeError by invalid key.
652 def test_result_with_hash_with_invalid_keys_raises_type_error
653 erb = @erb.new("<%= 1 %>")
654 assert_raise(TypeError) { erb.result_with_hash({ 1 => "1" }) }
658 def test_half_working_comment_backward_compatibility
659 assert_nothing_raised do
660 @erb.new("<% # comment %>\n").result
664 # [deprecated] These interfaces will be removed later
665 def test_deprecated_interface_warnings
666 [nil, 0, 1, 2].each do |safe|
667 assert_warn(/2nd argument of ERB.new is deprecated/) do
672 [nil, '', '%', '%<>'].each do |trim|
673 assert_warn(/3rd argument of ERB.new is deprecated/) do
674 ERB.new('', nil, trim)
678 [nil, '_erbout', '_hamlout'].each do |eoutvar|
679 assert_warn(/4th argument of ERB.new is deprecated/) do
680 ERB.new('', nil, nil, eoutvar)
685 def test_prohibited_marshal_dump
687 assert_raise(TypeError) {Marshal.dump(erb)}
690 def test_prohibited_marshal_load
692 erb.instance_variable_set(:@src, "")
693 erb.instance_variable_set(:@lineno, 1)
694 erb.instance_variable_set(:@_init, true)
695 erb = Marshal.load(Marshal.dump(erb))
696 assert_raise(ArgumentError) {erb.result}
700 class TestERBCoreWOStrScan < TestERBCore
702 @save_map = ERB::Compiler::Scanner.instance_variable_get('@scanner_map')
703 map = {[nil, false]=>ERB::Compiler::SimpleScanner}
704 ERB::Compiler::Scanner.instance_variable_set('@scanner_map', map)
709 ERB::Compiler::Scanner.instance_variable_set('@scanner_map', @save_map)