# frozen_string_literal: false require_relative "rexml_test_utils" require 'rexml/sax2listener' require 'rexml/parsers/sax2parser' require 'rexml/document' module REXMLTests class SAX2Tester < Test::Unit::TestCase include REXMLTestUtils include REXML def test_characters d = Document.new( "@blah@" ) txt = d.root.text p = Parsers::SAX2Parser.new "@blah@" p.listen(:characters) {|x| assert_equal txt, x} p.listen(:characters, ["A"]) {|x| assert_equal txt,x} p.parse end def test_entity_replacement source = ' ]>&la;&lala;' sax = Parsers::SAX2Parser.new( source ) results = [] sax.listen(:characters) {|x| results << x } sax.parse assert_equal 2, results.size assert_equal '1234', results[0] assert_equal '--1234--', results[1] end def test_sax2 File.open(fixture_path("documentation.xml")) do |f| parser = Parsers::SAX2Parser.new( f ) # Listen to all events on the following elements count = 0 blok = proc { |uri,localname,qname,attributes| assert %w{ bugs todo }.include?(localname), "Mismatched name; we got '#{qname}'\nArgs were:\n\tURI: #{uri}\n\tLOCALNAME: #{localname}\n\tQNAME: #{qname}\n\tATTRIBUTES: #{attributes.inspect}\n\tSELF=#{blok}" count += 1 } start_document = 0 end_document = 0 parser.listen( :start_document ) { start_document += 1 } parser.listen( :end_document ) { end_document += 1 } parser.listen( :start_element, %w{ changelog bugs todo }, &blok ) # Listen to all events on the following elements. Synonymous with # listen( :start_element, %w{ ... } ) parser.listen( %w{ changelog bugs todo }, &blok ) # Listen for all start element events parser.listen( :start_element ) { |uri,localname,qname,attributes| } listener = MySAX2Listener.new # Listen for all events parser.listen( listener ) # Listen for all events on the given elements. Does not include children # events. Regular expressions work as well! parser.listen( %w{ /change/ bugs todo }, listener ) # Test the deafening method blok = proc { |uri,localname,qname,attributes| assert_fail "This listener should have been deafened!" } parser.listen( %w{ changelog }, &blok ) parser.deafen( &blok ) tc = 0 parser.listen( :characters, %w{version} ) {|text| assert(text=~/@ANT_VERSION@/, "version was '#{text}'") tc += 1 } begin parser.parse rescue => exception if exception.kind_of? Test::Unit::AssertionFailedError raise exception end puts $! puts exception.backtrace end assert_equal 2, count assert_equal 1, tc assert_equal 1, start_document assert_equal 1, end_document end end # used by test_simple_doctype_listener # submitted by Jeff Barczewski class SimpleDoctypeListener include REXML::SAX2Listener attr_reader :name, :pub_sys, :long_name, :uri def initialize @name = @pub_sys = @long_name = @uri = nil end def doctype(name, pub_sys, long_name, uri) @name = name @pub_sys = pub_sys @long_name = long_name @uri = uri end end # test simple non-entity doctype in sax listener # submitted by Jeff Barczewski def test_simple_doctype_listener xml = <<-END Hello, world! END parser = Parsers::SAX2Parser.new(xml) dtl = SimpleDoctypeListener.new parser.listen(dtl) tname = nil tpub_sys = nil tlong_name = nil turi = nil parser.listen(:doctype) do |name, pub_sys, long_name, uri| tname = name tpub_sys = pub_sys tlong_name = long_name turi = uri end parser.parse assert_equal 'greeting', tname, 'simple doctype block listener failed - incorrect name' assert_equal 'PUBLIC', tpub_sys, 'simple doctype block listener failed - incorrect pub_sys' assert_equal 'Hello Greeting DTD', tlong_name, 'simple doctype block listener failed - incorrect long_name' assert_equal 'http://foo/hello.dtd', turi, 'simple doctype block listener failed - incorrect uri' assert_equal 'greeting', dtl.name, 'simple doctype listener failed - incorrect name' assert_equal 'PUBLIC', dtl.pub_sys, 'simple doctype listener failed - incorrect pub_sys' assert_equal 'Hello Greeting DTD', dtl.long_name, 'simple doctype listener failed - incorrect long_name' assert_equal 'http://foo/hello.dtd', dtl.uri, 'simple doctype listener failed - incorrect uri' end # test doctype with missing name, should throw ParseException # submitted by Jeff Barczewseki def test_doctype_with_mising_name_throws_exception xml = <<-END Hello, world! END parser = Parsers::SAX2Parser.new(xml) assert_raise(REXML::ParseException, 'doctype missing name did not throw ParseException') do parser.parse end end class KouListener include REXML::SAX2Listener attr_accessor :sdoc, :edoc attr_reader :selem, :decl, :pi def initialize @sdoc = @edoc = @selem = false @decl = 0 @pi = 0 end def start_document @sdoc = true end def end_document @edoc = true end def xmldecl( *arg ) @decl += 1 end def processing_instruction( *arg ) @pi += 1 end def start_element( *arg ) @selem = true end end # Submitted by Kou def test_begin_end_document parser = Parsers::SAX2Parser.new("") kl = KouListener.new parser.listen(kl) sd = false ed = false parser.listen(:start_document) { sd = true } parser.listen(:end_document) { ed = true } parser.parse assert( sd, ':start_document block failed' ) assert( ed, ':end_document block failed' ) assert( kl.sdoc, ':start_document listener failed' ) assert( kl.edoc, ':end_document listener failed' ) end # Submitted by Kou def test_listen_before_start # FIXME: the following comment should be a test for validity. (The xml declaration # is invalid). #parser = Parsers::SAX2Parser.new( "") parser = Parsers::SAX2Parser.new( "") k1 = KouListener.new parser.listen( k1 ) xmldecl = false pi = 0 parser.listen( :xmldecl ) { xmldecl = true } parser.listen( :processing_instruction ) { pi += 1 } parser.parse assert( xmldecl, ':xmldecl failed' ) assert_equal( 2, pi, ':processing_instruction failed' ) assert( k1.decl, 'Listener for xmldecl failed' ) assert_equal( 2, k1.pi, 'Listener for processing instruction failed' ) end def test_socket require 'socket' TCPServer.open('127.0.0.1', 0) do |server| TCPSocket.open('127.0.0.1', server.addr[1]) do |socket| ok = false session = server.accept begin session << '' parser = REXML::Parsers::SAX2Parser.new(socket) Fiber.new do parser.listen(:start_element) do ok = true Fiber.yield end parser.parse end.resume assert(ok) ensure session.close end end end end def test_char_ref_sax2() parser = REXML::Parsers::SAX2Parser.new('ü') result = nil parser.listen(:characters) {|text| result = text.unpack('U*')} parser.parse() assert_equal(1, result.size) assert_equal(252, result[0]) end def test_char_ref_dom() doc = REXML::Document.new('ü') result = doc.root.text.unpack('U*') assert_equal(1, result.size) assert_equal(252, result[0]) end class Ticket68 include REXML::SAX2Listener end def test_ticket_68 File.open(fixture_path('ticket_68.xml')) do |f| parser = REXML::Parsers::SAX2Parser.new(f) parser.listen( Ticket68.new ) begin parser.parse rescue p parser.source.position p parser.source.current_line puts $!.backtrace.join("\n") flunk $!.message end end end end class MySAX2Listener include REXML::SAX2Listener end end