PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/test/erb/test_erb.rb

http://github.com/ruby/ruby
Ruby | 717 lines | 705 code | 8 blank | 4 comment | 0 complexity | 85256275712c878de4c51f2d32e315e1 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # -*- coding: us-ascii -*-
  2. # frozen_string_literal: false
  3. require 'test/unit'
  4. require 'erb'
  5. require 'stringio'
  6. class TestERB < Test::Unit::TestCase
  7. class MyError < RuntimeError ; end
  8. def test_without_filename
  9. erb = ERB.new("<% raise ::TestERB::MyError %>")
  10. e = assert_raise(MyError) {
  11. erb.result
  12. }
  13. assert_match(/\A\(erb\):1\b/, e.backtrace[0])
  14. end
  15. def test_with_filename
  16. erb = ERB.new("<% raise ::TestERB::MyError %>")
  17. erb.filename = "test filename"
  18. e = assert_raise(MyError) {
  19. erb.result
  20. }
  21. assert_match(/\Atest filename:1\b/, e.backtrace[0])
  22. end
  23. # [deprecated] This will be removed later
  24. def test_without_filename_with_safe_level
  25. erb = EnvUtil.suppress_warning do
  26. ERB.new("<% raise ::TestERB::MyError %>", 1)
  27. end
  28. e = assert_raise(MyError) {
  29. erb.result
  30. }
  31. assert_match(/\A\(erb\):1\b/, e.backtrace[0])
  32. end
  33. # [deprecated] This will be removed later
  34. def test_with_filename_and_safe_level
  35. erb = EnvUtil.suppress_warning do
  36. ERB.new("<% raise ::TestERB::MyError %>", 1)
  37. end
  38. erb.filename = "test filename"
  39. e = assert_raise(MyError) {
  40. erb.result
  41. }
  42. assert_match(/\Atest filename:1\b/, e.backtrace[0])
  43. end
  44. def test_with_filename_lineno
  45. erb = ERB.new("<% raise ::TestERB::MyError %>")
  46. erb.filename = "test filename"
  47. erb.lineno = 100
  48. e = assert_raise(MyError) {
  49. erb.result
  50. }
  51. assert_match(/\Atest filename:101\b/, e.backtrace[0])
  52. end
  53. def test_with_location
  54. erb = ERB.new("<% raise ::TestERB::MyError %>")
  55. erb.location = ["test filename", 200]
  56. e = assert_raise(MyError) {
  57. erb.result
  58. }
  59. assert_match(/\Atest filename:201\b/, e.backtrace[0])
  60. end
  61. def test_html_escape
  62. assert_equal(" !&quot;\#$%&amp;&#39;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
  63. ERB::Util.html_escape(" !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"))
  64. assert_equal("", ERB::Util.html_escape(""))
  65. assert_equal("abc", ERB::Util.html_escape("abc"))
  66. assert_equal("&lt;&lt;", ERB::Util.html_escape("<\<"))
  67. assert_equal("", ERB::Util.html_escape(nil))
  68. assert_equal("123", ERB::Util.html_escape(123))
  69. end
  70. def test_concurrent_default_binding
  71. template1 = 'one <%= ERB.new(template2).result %>'
  72. eval 'template2 = "two"', TOPLEVEL_BINDING
  73. bug7046 = '[ruby-core:47638]'
  74. assert_equal("one two", ERB.new(template1).result, bug7046)
  75. end
  76. end
  77. class TestERBCore < Test::Unit::TestCase
  78. def setup
  79. @erb = ERB
  80. end
  81. def test_version
  82. assert_equal(String, @erb.version.class)
  83. end
  84. def test_core
  85. # [deprecated] Fix initializer later
  86. EnvUtil.suppress_warning do
  87. _test_core(nil)
  88. _test_core(0)
  89. _test_core(1)
  90. end
  91. end
  92. def _test_core(safe)
  93. erb = @erb.new("hello")
  94. assert_equal("hello", erb.result)
  95. erb = @erb.new("hello", safe, 0)
  96. assert_equal("hello", erb.result)
  97. erb = @erb.new("hello", safe, 1)
  98. assert_equal("hello", erb.result)
  99. erb = @erb.new("hello", safe, 2)
  100. assert_equal("hello", erb.result)
  101. src = <<EOS
  102. %% hi
  103. = hello
  104. <% 3.times do |n| %>
  105. % n=0
  106. * <%= n %>
  107. <% end %>
  108. EOS
  109. ans = <<EOS
  110. %% hi
  111. = hello
  112. % n=0
  113. * 0
  114. % n=0
  115. * 1
  116. % n=0
  117. * 2
  118. EOS
  119. erb = @erb.new(src)
  120. assert_equal(ans, erb.result)
  121. erb = @erb.new(src, safe, 0)
  122. assert_equal(ans, erb.result)
  123. erb = @erb.new(src, safe, '')
  124. assert_equal(ans, erb.result)
  125. ans = <<EOS
  126. %% hi
  127. = hello
  128. % n=0
  129. * 0% n=0
  130. * 1% n=0
  131. * 2
  132. EOS
  133. erb = @erb.new(src, safe, 1)
  134. assert_equal(ans.chomp, erb.result)
  135. erb = @erb.new(src, safe, '>')
  136. assert_equal(ans.chomp, erb.result)
  137. ans = <<EOS
  138. %% hi
  139. = hello
  140. % n=0
  141. * 0
  142. % n=0
  143. * 1
  144. % n=0
  145. * 2
  146. EOS
  147. erb = @erb.new(src, safe, 2)
  148. assert_equal(ans, erb.result)
  149. erb = @erb.new(src, safe, '<>')
  150. assert_equal(ans, erb.result)
  151. ans = <<EOS
  152. % hi
  153. = hello
  154. * 0
  155. * 0
  156. * 0
  157. EOS
  158. erb = @erb.new(src, safe, '%')
  159. assert_equal(ans, erb.result)
  160. ans = <<EOS
  161. % hi
  162. = hello
  163. * 0* 0* 0
  164. EOS
  165. erb = @erb.new(src, safe, '%>')
  166. assert_equal(ans.chomp, erb.result)
  167. ans = <<EOS
  168. % hi
  169. = hello
  170. * 0
  171. * 0
  172. * 0
  173. EOS
  174. erb = @erb.new(src, safe, '%<>')
  175. assert_equal(ans, erb.result)
  176. end
  177. def test_trim_line1_with_carriage_return
  178. erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '>')
  179. assert_equal("line\r\n" * 3, erb.result)
  180. erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '%>')
  181. assert_equal("line\r\n" * 3, erb.result)
  182. end
  183. def test_trim_line2_with_carriage_return
  184. erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '<>')
  185. assert_equal("line\r\n" * 3, erb.result)
  186. erb = @erb.new("<% 3.times do %>\r\nline\r\n<% end %>\r\n", trim_mode: '%<>')
  187. assert_equal("line\r\n" * 3, erb.result)
  188. end
  189. def test_explicit_trim_line_with_carriage_return
  190. erb = @erb.new("<%- 3.times do -%>\r\nline\r\n<%- end -%>\r\n", trim_mode: '-')
  191. assert_equal("line\r\n" * 3, erb.result)
  192. erb = @erb.new("<%- 3.times do -%>\r\nline\r\n<%- end -%>\r\n", trim_mode: '%-')
  193. assert_equal("line\r\n" * 3, erb.result)
  194. end
  195. def test_invalid_trim_mode
  196. assert_warning(/#{__FILE__}:#{__LINE__ + 1}/) do
  197. @erb.new("", trim_mode: 'abc-def')
  198. end
  199. assert_warning(/Invalid ERB trim mode/) do
  200. @erb.new("", trim_mode: 'abc-def')
  201. end
  202. assert_warning(/Invalid ERB trim mode/) do
  203. @erb.new("", trim_mode: '%<')
  204. end
  205. assert_warning(/Invalid ERB trim mode/) do
  206. @erb.new("", trim_mode: '%<>-')
  207. end
  208. assert_warning(/Invalid ERB trim mode/) do
  209. @erb.new("", trim_mode: 3)
  210. end
  211. end
  212. def test_run
  213. out = StringIO.new
  214. orig, $stdout = $stdout, out
  215. num = 3
  216. @erb.new('<%= num * 3 %>').run(binding)
  217. $stdout = orig
  218. out.rewind
  219. assert_equal('9', out.read)
  220. return unless num # to remove warning
  221. end
  222. class Foo; end
  223. def test_def_class
  224. erb = @erb.new('hello')
  225. cls = erb.def_class
  226. assert_equal(Object, cls.superclass)
  227. assert_respond_to(cls.new, 'result')
  228. cls = erb.def_class(Foo)
  229. assert_equal(Foo, cls.superclass)
  230. assert_respond_to(cls.new, 'result')
  231. cls = erb.def_class(Object, 'erb')
  232. assert_equal(Object, cls.superclass)
  233. assert_respond_to(cls.new, 'erb')
  234. end
  235. def test_percent
  236. src = <<EOS
  237. %n = 1
  238. <%= n%>
  239. EOS
  240. assert_equal("1\n", ERB.new(src, trim_mode: '%').result(binding))
  241. src = <<EOS
  242. <%
  243. %>
  244. EOS
  245. ans = "\n"
  246. assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
  247. src = "<%\n%>"
  248. # ans = "\n"
  249. ans = ""
  250. assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
  251. src = <<EOS
  252. <%
  253. n = 1
  254. %><%= n%>
  255. EOS
  256. assert_equal("1\n", ERB.new(src, trim_mode: '%').result(binding))
  257. src = <<EOS
  258. %n = 1
  259. %% <% n = 2
  260. n.times do |i|%>
  261. %% %%><%%<%= i%><%
  262. end%>
  263. %%%
  264. EOS
  265. ans = <<EOS
  266. %\s
  267. % %%><%0
  268. % %%><%1
  269. %%
  270. EOS
  271. assert_equal(ans, ERB.new(src, trim_mode: '%').result(binding))
  272. end
  273. def test_def_erb_method
  274. klass = Class.new
  275. klass.module_eval do
  276. extend ERB::DefMethod
  277. fname = File.join(File.dirname(File.expand_path(__FILE__)), 'hello.erb')
  278. def_erb_method('hello', fname)
  279. end
  280. assert_respond_to(klass.new, 'hello')
  281. assert_not_respond_to(klass.new, 'hello_world')
  282. erb = @erb.new('hello, world')
  283. klass.module_eval do
  284. def_erb_method('hello_world', erb)
  285. end
  286. assert_respond_to(klass.new, 'hello_world')
  287. end
  288. def test_def_method_without_filename
  289. klass = Class.new
  290. erb = ERB.new("<% raise ::TestERB::MyError %>")
  291. erb.filename = "test filename"
  292. assert_not_respond_to(klass.new, 'my_error')
  293. erb.def_method(klass, 'my_error')
  294. e = assert_raise(::TestERB::MyError) {
  295. klass.new.my_error
  296. }
  297. assert_match(/\A\(ERB\):1\b/, e.backtrace[0])
  298. end
  299. def test_def_method_with_fname
  300. klass = Class.new
  301. erb = ERB.new("<% raise ::TestERB::MyError %>")
  302. erb.filename = "test filename"
  303. assert_not_respond_to(klass.new, 'my_error')
  304. erb.def_method(klass, 'my_error', 'test fname')
  305. e = assert_raise(::TestERB::MyError) {
  306. klass.new.my_error
  307. }
  308. assert_match(/\Atest fname:1\b/, e.backtrace[0])
  309. end
  310. def test_def_module
  311. klass = Class.new
  312. klass.include ERB.new('<%= val %>').def_module('render(val)')
  313. assert_equal('1', klass.new.render(1))
  314. end
  315. def test_escape
  316. src = <<EOS
  317. 1.<%% : <%="<%%"%>
  318. 2.%%> : <%="%%>"%>
  319. 3.
  320. % x = "foo"
  321. <%=x%>
  322. 4.
  323. %% print "foo"
  324. 5.
  325. %% <%="foo"%>
  326. 6.<%="
  327. % print 'foo'
  328. "%>
  329. 7.<%="
  330. %% print 'foo'
  331. "%>
  332. EOS
  333. ans = <<EOS
  334. 1.<% : <%%
  335. 2.%%> : %>
  336. 3.
  337. foo
  338. 4.
  339. % print "foo"
  340. 5.
  341. % foo
  342. 6.
  343. % print 'foo'
  344. 7.
  345. %% print 'foo'
  346. EOS
  347. assert_equal(ans, ERB.new(src, trim_mode: '%').result)
  348. end
  349. def test_keep_lineno
  350. src = <<EOS
  351. Hello,\s
  352. % x = "World"
  353. <%= x%>
  354. % raise("lineno")
  355. EOS
  356. erb = ERB.new(src, trim_mode: '%')
  357. e = assert_raise(RuntimeError) {
  358. erb.result
  359. }
  360. assert_match(/\A\(erb\):4\b/, e.backtrace[0].to_s)
  361. src = <<EOS
  362. %>
  363. Hello,\s
  364. <% x = "World%%>
  365. "%>
  366. <%= x%>
  367. EOS
  368. ans = <<EOS
  369. %>Hello,\s
  370. World%>
  371. EOS
  372. assert_equal(ans, ERB.new(src, trim_mode: '>').result)
  373. ans = <<EOS
  374. %>
  375. Hello,\s
  376. World%>
  377. EOS
  378. assert_equal(ans, ERB.new(src, trim_mode: '<>').result)
  379. ans = <<EOS
  380. %>
  381. Hello,\s
  382. World%>
  383. EOS
  384. assert_equal(ans, ERB.new(src).result)
  385. src = <<EOS
  386. Hello,\s
  387. <% x = "World%%>
  388. "%>
  389. <%= x%>
  390. <% raise("lineno") %>
  391. EOS
  392. erb = ERB.new(src)
  393. e = assert_raise(RuntimeError) {
  394. erb.result
  395. }
  396. assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
  397. erb = ERB.new(src, trim_mode: '>')
  398. e = assert_raise(RuntimeError) {
  399. erb.result
  400. }
  401. assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
  402. erb = ERB.new(src, trim_mode: '<>')
  403. e = assert_raise(RuntimeError) {
  404. erb.result
  405. }
  406. assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
  407. src = <<EOS
  408. % y = 'Hello'
  409. <%- x = "World%%>
  410. "-%>
  411. <%= x %><%- x = nil -%>\s
  412. <% raise("lineno") %>
  413. EOS
  414. erb = ERB.new(src, trim_mode: '-')
  415. e = assert_raise(RuntimeError) {
  416. erb.result
  417. }
  418. assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
  419. erb = ERB.new(src, trim_mode: '%-')
  420. e = assert_raise(RuntimeError) {
  421. erb.result
  422. }
  423. assert_match(/\A\(erb\):5\b/, e.backtrace[0].to_s)
  424. end
  425. def test_explicit
  426. src = <<EOS
  427. <% x = %w(hello world) -%>
  428. NotSkip <%- y = x -%> NotSkip
  429. <% x.each do |w| -%>
  430. <%- up = w.upcase -%>
  431. * <%= up %>
  432. <% end -%>
  433. <%- z = nil -%> NotSkip <%- z = x %>
  434. <%- z.each do |w| -%>
  435. <%- down = w.downcase -%>
  436. * <%= down %>
  437. <%- up = w.upcase -%>
  438. * <%= up %>
  439. <%- end -%>
  440. KeepNewLine <%- z = nil -%>\s
  441. EOS
  442. ans = <<EOS
  443. NotSkip NotSkip
  444. * HELLO
  445. * WORLD
  446. NotSkip\s
  447. * hello
  448. * HELLO
  449. * world
  450. * WORLD
  451. KeepNewLine \s
  452. EOS
  453. assert_equal(ans, ERB.new(src, trim_mode: '-').result)
  454. assert_equal(ans, ERB.new(src, trim_mode: '-%').result)
  455. end
  456. def test_url_encode
  457. assert_equal("Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide",
  458. ERB::Util.url_encode("Programming Ruby: The Pragmatic Programmer's Guide"))
  459. assert_equal("%A5%B5%A5%F3%A5%D7%A5%EB",
  460. ERB::Util.url_encode("\xA5\xB5\xA5\xF3\xA5\xD7\xA5\xEB".force_encoding("EUC-JP")))
  461. assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
  462. ERB::Util.url_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
  463. "should not escape any unreserved characters, as per RFC3986 Section 2.3")
  464. end
  465. def test_percent_after_etag
  466. assert_equal("1%", @erb.new("<%= 1 %>%", trim_mode: "%").result)
  467. end
  468. def test_token_extension
  469. extended_erb = Class.new(ERB)
  470. extended_erb.module_eval do
  471. def make_compiler(trim_mode)
  472. compiler = Class.new(ERB::Compiler)
  473. compiler.module_eval do
  474. def compile_stag(stag, out, scanner)
  475. case stag
  476. when '<%=='
  477. scanner.stag = stag
  478. add_put_cmd(out, content) if content.size > 0
  479. self.content = ''
  480. else
  481. super
  482. end
  483. end
  484. def compile_content(stag, out)
  485. case stag
  486. when '<%=='
  487. out.push("#{@insert_cmd}(::ERB::Util.html_escape(#{content}))")
  488. else
  489. super
  490. end
  491. end
  492. def make_scanner(src)
  493. scanner = Class.new(ERB::Compiler::SimpleScanner)
  494. scanner.module_eval do
  495. def stags
  496. ['<%=='] + super
  497. end
  498. end
  499. scanner.new(src, @trim_mode, @percent)
  500. end
  501. end
  502. compiler.new(trim_mode)
  503. end
  504. end
  505. src = <<~EOS
  506. <% tag = '<>' \%>
  507. <\%= tag \%>
  508. <\%== tag \%>
  509. EOS
  510. ans = <<~EOS
  511. <>
  512. &lt;&gt;
  513. EOS
  514. assert_equal(ans, extended_erb.new(src).result)
  515. end
  516. def test_frozen_string_literal
  517. bug12031 = '[ruby-core:73561] [Bug #12031]'
  518. e = @erb.new("<%#encoding: us-ascii%>a")
  519. e.src.sub!(/\A#(?:-\*-)?(.*)(?:-\*-)?/) {
  520. '# -*- \1; frozen-string-literal: true -*-'
  521. }
  522. assert_equal("a", e.result, bug12031)
  523. %w(false true).each do |flag|
  524. erb = @erb.new("<%#frozen-string-literal: #{flag}%><%=''.frozen?%>")
  525. assert_equal(flag, erb.result)
  526. end
  527. end
  528. def test_result_with_hash
  529. erb = @erb.new("<%= foo %>")
  530. assert_equal("1", erb.result_with_hash(foo: "1"))
  531. end
  532. def test_result_with_hash_does_not_use_caller_local_variables
  533. erb = @erb.new("<%= foo %>")
  534. foo = 1
  535. assert_raise(NameError) { erb.result_with_hash({}) }
  536. assert_equal("1", erb.result_with_hash(foo: foo))
  537. end
  538. def test_result_with_hash_does_not_modify_caller_binding
  539. erb = @erb.new("<%= foo %>")
  540. erb.result_with_hash(foo: "1")
  541. assert_equal(false, binding.local_variable_defined?(:foo))
  542. end
  543. def test_result_with_hash_does_not_modify_toplevel_binding
  544. erb = @erb.new("<%= foo %>")
  545. erb.result_with_hash(foo: "1")
  546. assert_equal(false, TOPLEVEL_BINDING.local_variable_defined?(:foo))
  547. TOPLEVEL_BINDING.eval 'template2 = "two"'
  548. erb = @erb.new("<%= template2 %>")
  549. erb.result_with_hash(template2: "TWO")
  550. assert_equal "two", TOPLEVEL_BINDING.local_variable_get("template2")
  551. end
  552. # This depends on the behavior that #local_variable_set raises TypeError by invalid key.
  553. def test_result_with_hash_with_invalid_keys_raises_type_error
  554. erb = @erb.new("<%= 1 %>")
  555. assert_raise(TypeError) { erb.result_with_hash({ 1 => "1" }) }
  556. end
  557. # Bug#14243
  558. def test_half_working_comment_backward_compatibility
  559. assert_nothing_raised do
  560. @erb.new("<% # comment %>\n").result
  561. end
  562. end
  563. # [deprecated] These interfaces will be removed later
  564. def test_deprecated_interface_warnings
  565. [nil, 0].each do |safe|
  566. assert_warning(/2nd argument of ERB.new is deprecated/) do
  567. ERB.new('', safe)
  568. end
  569. end
  570. [1, 2].each do |safe|
  571. assert_warn(/2nd argument of ERB.new is deprecated/) do
  572. ERB.new('', safe)
  573. end
  574. end
  575. [nil, '', '%', '%<>'].each do |trim|
  576. assert_warning(/3rd argument of ERB.new is deprecated/) do
  577. ERB.new('', nil, trim)
  578. end
  579. end
  580. [nil, '_erbout', '_hamlout'].each do |eoutvar|
  581. assert_warning(/4th argument of ERB.new is deprecated/) do
  582. ERB.new('', nil, nil, eoutvar)
  583. end
  584. end
  585. end
  586. def test_prohibited_marshal_dump
  587. erb = ERB.new("")
  588. assert_raise(TypeError) {Marshal.dump(erb)}
  589. end
  590. def test_prohibited_marshal_load
  591. erb = ERB.allocate
  592. erb.instance_variable_set(:@src, "")
  593. erb.instance_variable_set(:@lineno, 1)
  594. erb.instance_variable_set(:@_init, true)
  595. erb = Marshal.load(Marshal.dump(erb))
  596. assert_raise(ArgumentError) {erb.result}
  597. end
  598. end
  599. class TestERBCoreWOStrScan < TestERBCore
  600. def setup
  601. @save_map = ERB::Compiler::Scanner.instance_variable_get('@scanner_map')
  602. map = {[nil, false]=>ERB::Compiler::SimpleScanner}
  603. ERB::Compiler::Scanner.instance_variable_set('@scanner_map', map)
  604. super
  605. end
  606. def teardown
  607. ERB::Compiler::Scanner.instance_variable_set('@scanner_map', @save_map)
  608. end
  609. end