1# frozen_string_literal: false 2require "test/unit/testcase" 3 4require 'rexml/document' 5require 'rexml/entity' 6require 'rexml/source' 7 8module REXMLTests 9 class EntityTester < Test::Unit::TestCase 10 def test_parse_general_decl 11 simple = "<!ENTITY foo 'bar'>" 12 simple =~ /#{REXML::Entity::GEDECL}/ 13 assert $& 14 assert_equal simple, $& 15 16 REXML::Entity::ENTITYDECL =~ simple 17 assert REXML::Entity::matches?(simple) 18 match = REXML::Entity::ENTITYDECL.match(simple) 19 assert_equal 'foo', match[1] 20 assert_equal "'bar'", match[2] 21 22 simple = '<!ENTITY Pub-Status 23 "This is a pre-release of the specification.">' 24 assert REXML::Entity::matches?(simple) 25 match = REXML::Entity::ENTITYDECL.match(simple) 26 assert_equal 'Pub-Status', match[1] 27 assert_equal '"This is a pre-release of the specification."', match[2] 28 29 txt = '"This is a 30 pre-release of <the> specification."' 31 simple = "<!ENTITY Pub-Status 32 #{txt}>" 33 assert REXML::Entity::matches?(simple) 34 match = REXML::Entity::ENTITYDECL.match(simple) 35 assert_equal 'Pub-Status', match[1] 36 assert_equal txt, match[2] 37 end 38 39 def test_parse_external_decl 40 zero = '<!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml" >' 41 one = '<!ENTITY open-hatch 42 SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">' 43 two = '<!ENTITY open-hatch 44 PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" 45 "http://www.textuality.com/boilerplate/OpenHatch.xml">' 46 three = '<!ENTITY hatch-pic 47 SYSTEM "../grafix/OpenHatch.gif" 48 NDATA gif >' 49 assert REXML::Entity::matches?(zero) 50 assert REXML::Entity::matches?(one) 51 assert REXML::Entity::matches?(two) 52 assert REXML::Entity::matches?(three) 53 end 54 55 def test_parse_entity 56 one = %q{<!ENTITY % YN '"Yes"'>} 57 two = %q{<!ENTITY WhatHeSaid "He said %YN;">} 58 assert REXML::Entity::matches?(one) 59 assert REXML::Entity::matches?(two) 60 end 61 62 def test_constructor 63 one = [ %q{<!ENTITY % YN '"Yes"'>}, 64 %q{<!ENTITY % YN2 "Yes">}, 65 %q{<!ENTITY WhatHeSaid "He said %YN;">}, 66 '<!ENTITY open-hatch 67 SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">', 68 '<!ENTITY open-hatch2 69 PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" 70 "http://www.textuality.com/boilerplate/OpenHatch.xml">', 71 '<!ENTITY hatch-pic 72 SYSTEM "../grafix/OpenHatch.gif" 73 NDATA gif>' ] 74 source = %q{<!DOCTYPE foo [ 75 <!ENTITY % YN '"Yes"'> 76 <!ENTITY % YN2 "Yes"> 77 <!ENTITY WhatHeSaid "He said %YN;"> 78 <!ENTITY open-hatch 79 SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml"> 80 <!ENTITY open-hatch2 81 PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" 82 "http://www.textuality.com/boilerplate/OpenHatch.xml"> 83 <!ENTITY hatch-pic 84 SYSTEM "../grafix/OpenHatch.gif" 85 NDATA gif> 86 ]>} 87 88 d = REXML::Document.new( source ) 89 dt = d.doctype 90 c = 0 91 dt.each do |child| 92 if child.kind_of? REXML::Entity 93 str = one[c].tr("\r\n\t", ' ').squeeze(" ") 94 assert_equal str, child.to_s 95 c+=1 96 end 97 end 98 end 99 100 def test_replace_entities 101 source = "<!DOCTYPE blah [\n<!ENTITY foo \"bar\">\n]><a>&foo;</a>" 102 doc = REXML::Document.new(source) 103 assert_equal 'bar', doc.root.text 104 out = '' 105 doc.write out 106 assert_equal source, out 107 end 108 109 def test_entity_string_limit 110 template = '<!DOCTYPE bomb [ <!ENTITY a "^" > ]> <bomb>$</bomb>' 111 len = 5120 # 5k per entity 112 template.sub!(/\^/, "B" * len) 113 114 # 10k is OK 115 entities = '&a;' * 2 # 5k entity * 2 = 10k 116 xmldoc = REXML::Document.new(template.sub(/\$/, entities)) 117 assert_equal(len * 2, xmldoc.root.text.bytesize) 118 119 # above 10k explodes 120 entities = '&a;' * 3 # 5k entity * 2 = 15k 121 xmldoc = REXML::Document.new(template.sub(/\$/, entities)) 122 assert_raise(RuntimeError) do 123 xmldoc.root.text 124 end 125 end 126 127 def test_entity_string_limit_for_parameter_entity 128 template = '<!DOCTYPE bomb [ <!ENTITY % a "^" > <!ENTITY bomb "$" > ]><root/>' 129 len = 5120 # 5k per entity 130 template.sub!(/\^/, "B" * len) 131 132 # 10k is OK 133 entities = '%a;' * 2 # 5k entity * 2 = 10k 134 REXML::Document.new(template.sub(/\$/, entities)) 135 136 # above 10k explodes 137 entities = '%a;' * 3 # 5k entity * 2 = 15k 138 assert_raise(REXML::ParseException) do 139 REXML::Document.new(template.sub(/\$/, entities)) 140 end 141 end 142 143 def test_raw 144 source = '<!DOCTYPE foo [ 145<!ENTITY ent "replace"> 146]><a>replace &ent;</a>' 147 doc = REXML::Document.new( source, {:raw=>:all}) 148 assert_equal('replace &ent;', doc.root.get_text.to_s) 149 assert_equal(source, doc.to_s) 150 end 151 152 def test_lazy_evaluation 153 source = '<!DOCTYPE foo [ 154<!ENTITY ent "replace"> 155]><a>replace &ent;</a>' 156 doc = REXML::Document.new( source ) 157 assert_equal(source, doc.to_s) 158 assert_equal("replace replace", doc.root.text) 159 assert_equal(source, doc.to_s) 160 end 161 162 # Contributed (not only test, but bug fix!!) by Kouhei Sutou 163 def test_entity_replacement 164 source = %q{<!DOCTYPE foo [ 165 <!ENTITY % YN '"Yes"'> 166 <!ENTITY WhatHeSaid "He said %YN;">]> 167 <a>&WhatHeSaid;</a>} 168 169 d = REXML::Document.new( source ) 170 dt = d.doctype 171 assert_equal( '"Yes"', dt.entities[ "YN" ].value ) 172 assert_equal( 'He said "Yes"', dt.entities[ "WhatHeSaid" ].value ) 173 assert_equal( 'He said "Yes"', d.elements[1].text ) 174 end 175 176 # More unit tests from Kouhei. I looove users who give me unit tests. 177 def test_entity_insertions 178 assert_equal("&", REXML::Text.new("&", false, nil, true).to_s) 179 #assert_equal("&", REXML::Text.new("&", false, false).to_s) 180 end 181 182 def test_single_pass_unnormalization # ticket 123 183 assert_equal '&&', REXML::Text::unnormalize('&amp;&') 184 end 185 186 def test_entity_filter 187 document = REXML::Document.new(<<-XML) 188<!DOCTYPE root [ 189<!ENTITY copy "(c)"> 190<!ENTITY release-year "2013"> 191]> 192<root/> 193XML 194 respect_whitespace = false 195 parent = document.root 196 raw = false 197 entity_filter = ["copy"] 198 assert_equal("(c) &release-year;", 199 REXML::Text.new("(c) 2013", 200 respect_whitespace, 201 parent, 202 raw, 203 entity_filter).to_s) 204 end 205 end 206end 207