#!/usr/bin/ruby -I../rexml
################################################################################
#                                                                              #
#  This file can be used to run REXML against the Oasis test suite.            #
#  Make sure that you set the XMLCONFDIR to the correct location before        #
#  running.                                                                    #
#                                                                              #
################################################################################

# The following constant should point to the 'xmlconf' directory of the Oasis
# test suite.
XMLCONFDIR = "../../XML-Test-Suite/xmlconf/"

################################################################################
#                                                                              #
# Uncomment the following block to test any other Ruby XML parsers you may have#
# installed.                                                                   #
#                                                                              #
################################################################################
=begin
begin
	require 'xmlparser'              ## xmlparser
	xmlparser = true
rescue Exception
	xmlparser = false
end
begin
	require 'nqxml/streamingparser'  ## nqxml
	nqxml = true
rescue Exception
	nqxml = false
end
begin
	require 'xmlscan/parser'         ## xmlscan
	xmlscan = true
rescue Exception
	xmlscan = false
end

=end
xmlparser = nqxml = xmlscan = false

begin
	require 'rexml/document'         ## rexml
	require 'rexml/sax2parser'
	require 'rexml/pullparser'
	rexml = true
rescue Exception
	puts $!
	rexml = false
end

@@debug = false
@@invalid_tests = false
if ARGV.size > 0 
	args = ARGV.join
	if args.include? "d"
		puts "Debugging on"
		@@debug = true
	end
	if args.include? "f"
		puts "Test invalid on"
		@@invalid_tests = true
	end
end


class XMLConf
	def initialize(); @result = Hash.new(); end
	attr_reader :result
	def clear();      @result.clear;        end
	# "pass" lets us check for invalid files as well; that is, by default,
	# pass is true and we're checking a valid file.  If pass is false, however,
	# we're checking an invalid file which *should* fail.
	def check(file, pass=true)
		check = pass
		File.open(file){|f|
			str = f.read
			begin
				parse(str)
				puts "(#{file})" if not pass and @@debug
			rescue Exception
				if pass and @@debug
					print "##############################################\n"
					print $!,"(#{file})\n"
					print $@.join("\n"),"\n"
				end
				check = !pass
			end
		}
		@result[file] = check
	end

	## def parser(str); end  ## Abstract Method.
end

tests = []
if xmlparser
	class XMLParserConf < XMLConf
		def parse(str); XMLParser.new.parse(str);  end
	end
	tests << XMLParserConf.new
end
if nqxml
	class NQXMLConf < XMLConf
		def parse(str); NQXML::StreamingParser.new(str).each{|e| e}; end
	end
	tests << NQXMLConf.new
end
if rexml
	class REXMLConf < XMLConf
		def parse(str); REXML::Document.new(str); end
	end
	tests << REXMLConf.new

	class REXMLPPConf < XMLConf
		def parse(str)
			pp = REXML::PullParser.new(str)
			until pp.empty?
				pp.next
			end
		end
	end
	tests << REXMLPPConf.new

	class REXMLSAXConf < XMLConf
		def parse(str)
			sp = REXML::SAX2Parser.new(str)
			sp.parse
		end
	end
	tests << REXMLSAXConf.new
end
if xmlscan
	class TestVisitor
		include XMLScan::XMLVisitor
			def parse_error(path, lineno, msg)
				if msg !~ /internal DTD subset is not supported/ ## it's just warning.
					raise "parse error: #{msg}(#{path})"
				end
			end
		def wellformed_error(path, lineno, msg); raise "WFC error: #{msg}";end
		def ns_error(path, lineno, msg); raise "NS error: #{msg}"; end
		def warning(*args); end
	end

	class XMLScanConf < XMLConf
		def parse(str); XMLScan::XMLParser.new(TestVisitor.new).parse(str); end
	end
	tests << XMLScanConf.new
end

### main

def success_num(result)
	result.find_all{|key,value| value == true}.length
end

def fail_num(result)
	result.find_all{|key,value| value == false}.length
end

puts "Checking valid tests..."
valid = Dir.glob(XMLCONFDIR+"*/valid/*/*.xml")
valid.concat(Dir.glob(XMLCONFDIR+"oasis/p*pass*.xml"))
valid.each { |file|
	#puts "Testing #{file}"
	tests.each { |test| 
		test.check(file) 
	}
}

if @@invalid_tests
	puts "Checking fail tests..."
	invalid = Dir.glob(XMLCONFDIR+"oasis/p*fail*.xml")
	#invalid.concat(Dir.glob(XMLCONFDIR+"*/invalid/*/*.xml"))
	invalid.each{ |file|
		tests.each { |test| test.check(file, false) }
	}
end
## end

if tests.length == 0
  puts "No tests."
  exit
end
total = tests[0].result.length
result_list = {}
tests.each { |c|
	result_list[ c.type.to_s.gsub(/Conf$/, "") ] = c.result
}

result_list.each{|name, result|
	print "*** #{name} ***","\n"
	printf("total   ...%3d\n",total)
	printf("success ...%3d (%2.1f%%)\n",
			success_num(result),
			Float(success_num(result)*100)/total)
	printf("failure ...%3d (%2.1f%%)\n",
			fail_num(result),
			Float(fail_num(result)*100)/total)
	result.each_key{|key| puts "\t#{key}" if result[key] == false}
}
