lib/minitest_log.rb in minitest_log-1.0.0 vs lib/minitest_log.rb in minitest_log-1.0.1
- old
+ new
@@ -2,13 +2,16 @@
require 'minitest/autorun'
require 'minitest/assertions'
require 'diff/lcs'
require_relative 'verdict_assertion'
+require_relative 'minitest_assertions_patch'
class MinitestLog
+ include REXML
+ include Minitest::Assertions
include VerdictAssertion
attr_accessor \
:assertions,
:counts,
@@ -19,57 +22,28 @@
:verdict_ids,
:xml_indentation,
:error_verdict,
:summary
- include REXML
- include Minitest::Assertions
-
class MinitestLogError < Exception; end
class NoBlockError < MinitestLogError; end
class DuplicateVerdictIdError < MinitestLogError; end
class IllegalElementNameError < MinitestLogError; end
class IllegalNewError < MinitestLogError; end
def initialize(file_path, options=Hash.new)
raise NoBlockError.new('No block given for MinitestLog#new.') unless (block_given?)
- default_options = Hash[
- :root_name => 'log',
- :xml_indentation => 2,
- :error_verdict => false,
- :summary => false
- ]
- options = default_options.merge(options)
- self.assertions = 0
self.file_path = file_path
- self.root_name = options[:root_name]
- self.xml_indentation = options[:xml_indentation]
- self.summary = options[:summary]
- self.error_verdict = options[:error_verdict] || false
- self.backtrace_filter = options[:backtrace_filter] || /minitest/
- self.file = File.open(self.file_path, 'w')
- log_puts("REMARK\tThis text log is the precursor for an XML log.")
- log_puts("REMARK\tIf the logged process completes, this text will be converted to XML.")
- log_puts("BEGIN\t#{self.root_name}")
- self.counts = Hash[
- :verdict => 0,
- :failure => 0,
- :error => 0,
- ]
- begin
- yield self
- rescue => x
- put_element('uncaught_exception', :timestamp, :class => x.class) do
- put_element('message', x.message)
- put_element('backtrace') do
- backtrace = filter_backtrace(x.backtrace)
- put_pre(backtrace.join("\n"))
- end
+ handle_options(options)
+ do_log do
+ begin
+ yield self
+ rescue => x
+ handle_exception(x)
end
end
- dispose
- nil
+ create_xml_log
end
def section(name, *args)
put_element('section', {:name => name}, *args) do
yield if block_given?
@@ -88,82 +62,16 @@
end
nil
end
def put_element(element_name = 'element', *args)
- if false ||
- caller[0].match(/minitest_log.rb/) ||
- caller[0].match(/verdict_assertion.rb/)
- # Make the element name special.
- element_name += '_'
- elsif element_name.end_with?('_')
- # Don't accept user's special.
- message = "Element name should not end with underscore: #{element_name}"
- raise IllegalElementNameError.new(message)
+ conditioned_element_name = condition_element_name(element_name, caller[0])
+ if block_given?
+ Element.new(self, conditioned_element_name, *args, &Proc.new)
else
- # Ok.
+ Element.new(self, conditioned_element_name, *args)
end
- attributes = {}
- pcdata = ''
- start_time = nil
- duration_to_be_included = false
- block_to_be_rescued = false
- args.each do |arg|
- case
- when arg.kind_of?(Hash)
- attributes.merge!(arg)
- when arg.kind_of?(String)
- pcdata += arg
- when arg == :timestamp
- attributes[:timestamp] = MinitestLog.timestamp
- when arg == :duration
- duration_to_be_included = true
- when arg == :rescue
- block_to_be_rescued = true
- else
- pcdata = pcdata + arg.inspect
- end
- end
- log_puts("BEGIN\t#{element_name}")
- put_attributes(attributes)
- unless pcdata.empty?
- # Guard against using a terminator that's a substring of pcdata.
- s = 'EOT'
- terminator = s
- while pcdata.match(terminator) do
- terminator += s
- end
- log_puts("PCDATA\t<<#{terminator}")
- log_puts(pcdata)
- log_puts(terminator)
- end
- start_time = Time.new if duration_to_be_included
- if block_given?
- if block_to_be_rescued
- begin
- yield
- rescue Exception => x
- put_element('rescued_exception', {:class => x.class, :message => x.message}) do
- put_element('backtrace') do
- backtrace = filter_backtrace(x.backtrace)
- put_pre(backtrace.join("\n"))
- end
- end
- self.counts[:error] += 1
- end
- else
- yield
- end
- end
- if start_time
- end_time = Time.now
- duration_f = end_time.to_f - start_time.to_f
- duration_s = format('%.3f', duration_f)
- put_attributes({:duration_seconds => duration_s})
- end
- log_puts("END\t#{element_name}")
- nil
end
def put_each_with_index(name, obj)
lines = ['']
obj.each_with_index do |item, i|
@@ -271,22 +179,38 @@
end
end
private
- def dispose
+ def do_log
+ begin_log
+ yield
+ end_log
+ end
- # Add a verdict for the error count, if needed.
+ def begin_log
+ self.counts = Hash[
+ :verdict => 0,
+ :failure => 0,
+ :error => 0,
+ ]
+ self.assertions = 0
+ self.file = File.open(self.file_path, 'w')
+ log_puts("REMARK\tThis text log is the precursor for an XML log.")
+ log_puts("REMARK\tIf the logged process completes, this text will be converted to XML.")
+ log_puts("BEGIN\t#{self.root_name}")
+ end
+
+ def end_log
if self.error_verdict
verdict_assert_equal?('error_count', 0, self.counts[:error])
end
-
- # Close the text log.
log_puts("END\t#{self.root_name}")
self.file.close
+ end
- # Create the xml log.
+ def create_xml_log
document = REXML::Document.new
File.open(self.file_path, 'r') do |file|
element = document
stack = Array.new
data_a = Array.new
@@ -372,14 +296,11 @@
args_hash.each_pair do |k, v|
put_element(k.to_s, {:class => v.class, :value => v.inspect})
end
if exception
self.counts[:failure] += 1
- # If the encoding is not UTF-8, a string will have been added.
- # Remove it, so that the message is the same on all platforms.
- conditioned_message = exception.message.gsub("# encoding: UTF-8\n", '')
- put_element('exception', {:class => exception.class, :message => conditioned_message}) do
+ put_element('exception', {:class => exception.class, :message => exception.message}) do
put_element('backtrace') do
backtrace = filter_backtrace(exception.backtrace)
put_pre(backtrace.join("\n"))
end
end
@@ -390,11 +311,11 @@
def put_attributes(attributes)
attributes.each_pair do |name, value|
value = case
when value.is_a?(String)
- value
+ value.gsub("\n", "\\n")
when value.is_a?(Symbol)
value.to_s
else
value.inspect
end
@@ -417,23 +338,31 @@
end
self.verdict_ids.add(verdict_id)
nil
end
- def put_cdata(text)
+ def put_cdata_or_pcdata(token, text)
# Guard against using a terminator that's a substring of the cdata.
s = 'EOT'
terminator = s
while text.match(terminator) do
terminator += s
end
- log_puts("CDATA\t<<#{terminator}")
+ log_puts("#{token}\t<<#{terminator}")
log_puts(text)
log_puts(terminator)
nil
end
+ def put_cdata(text)
+ put_cdata_or_pcdata('CDATA', text)
+ end
+
+ def put_pcdata(text)
+ put_cdata_or_pcdata('PCDATA', text)
+ end
+
def get_assertion_outcome(verdict_id, assertion_method, *assertion_args)
validate_verdict_id(verdict_id)
self.counts[:verdict] += 1
begin
if block_given?
@@ -469,12 +398,11 @@
ts = now.strftime('%Y-%m-%d-%a-%H.%M.%S')
usec_s = (now.usec / 1000).to_s
while usec_s.length < 3 do
usec_s = '0' + usec_s
end
- # noinspection RubyUnusedLocalVariable
- ts += ".#{usec_s}"
+ "#{ts}.#{usec_s}"
end
def assertion_method_for(verdict_method)
# Our verdict method name is just an assertion method name
# with prefixed 'verdict_' and suffixed '?'.
@@ -491,8 +419,164 @@
document = nil
File.open(file_path) do |file|
document = REXML::Document.new(file)
end
document
+ end
+
+ def condition_element_name(element_name, caller_0)
+ if caller_is_us?(caller_0)
+ conditioned_element_name = element_name + '_'
+ elsif element_name.end_with?('_')
+ message = "Element name should not end with underscore: #{element_name}"
+ raise IllegalElementNameError.new(message)
+ else
+ conditioned_element_name = element_name
+ end
+ conditioned_element_name
+ end
+
+ def caller_is_us?(caller_0)
+ caller_0.match(/minitest_log.rb/) || caller_0.match(/verdict_assertion.rb/)
+ end
+
+ def handle_options(options)
+ default_options = Hash[
+ :root_name => 'log',
+ :xml_indentation => 2,
+ :error_verdict => false,
+ :summary => false
+ ]
+ options = default_options.merge(options)
+ self.root_name = options[:root_name]
+ self.xml_indentation = options[:xml_indentation]
+ self.summary = options[:summary]
+ self.error_verdict = options[:error_verdict] || false
+ self.backtrace_filter = options[:backtrace_filter] || /minitest/
+ end
+
+ def handle_exception(x)
+ put_element('uncaught_exception', :timestamp, :class => x.class) do
+ put_element('message', x.message)
+ put_element('backtrace') do
+ backtrace = filter_backtrace(x.backtrace)
+ put_pre(backtrace.join("\n"))
+ end
+ end
+ end
+
+ class Element
+
+ attr_accessor \
+ :args,
+ :attributes,
+ :block_to_be_rescued,
+ :duration_to_be_included,
+ :element_name,
+ :log,
+ :pcdata,
+ :start_time
+
+ def initialize(log, element_name, *args)
+
+ self.log = log
+ self.element_name = element_name
+ self.args = args
+
+ self.attributes = {}
+ self.block_to_be_rescued = false
+ self.duration_to_be_included = false
+ self.pcdata = ''
+ self.start_time = nil
+
+ process_args
+ put_element do
+ put_attributes
+ put_pcdata
+ do_duration do
+ do_block(&Proc.new) if block_given?
+ end
+ end
+
+ end
+
+ def process_args
+ args.each do |arg|
+ case
+ when arg.kind_of?(Hash)
+ self.attributes.merge!(arg)
+ when arg.kind_of?(String)
+ self.pcdata += arg
+ when arg == :timestamp
+ self.attributes[:timestamp] = MinitestLog.timestamp
+ when arg == :duration
+ self.duration_to_be_included = true
+ when arg == :rescue
+ self.block_to_be_rescued = true
+ else
+ self.pcdata = self.pcdata + arg.inspect
+ end
+ end
+ end
+
+ def put_element
+ log_puts("BEGIN\t#{element_name}")
+ yield
+ log_puts("END\t#{element_name}")
+ end
+
+ def put_attributes
+ log_put_attributes(attributes)
+ end
+
+ def put_pcdata
+ unless pcdata.empty?
+ log.send(:put_pcdata, pcdata)
+ end
+ end
+
+ def do_duration
+ self.start_time = Time.new
+ yield
+ if duration_to_be_included
+ end_time = Time.now
+ duration_f = end_time.to_f - start_time.to_f
+ duration_s = format('%.3f', duration_f)
+ log_put_attributes({:duration_seconds => duration_s})
+ end
+ end
+
+ def do_block
+ if block_to_be_rescued
+ begin
+ yield
+ rescue Exception => x
+ log.put_element('rescued_exception', {:class => x.class, :message => x.message}) do
+ log.put_element('backtrace') do
+ backtrace = log_filter_backtrace(x.backtrace)
+ log.put_pre(backtrace.join("\n"))
+ end
+ end
+ log.counts[:error] += 1
+ end
+ else
+ yield
+ end
+ end
+
+ # The called methods are private.
+
+ def log_puts(s)
+ log.send(:log_puts, s)
+ end
+
+ def log_put_attributes(attributes)
+ log.send(:put_attributes, attributes)
+ end
+
+ def log_filter_backtrace(backtrace)
+ log.send(:filter_backtrace, backtrace)
+ end
+
end
end