diff options
Diffstat (limited to 'test/assert.rb')
| -rw-r--r-- | test/assert.rb | 373 |
1 files changed, 245 insertions, 128 deletions
diff --git a/test/assert.rb b/test/assert.rb index a9baae5e1..c493cbbc0 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -1,17 +1,47 @@ +$undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 +$skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) -# Implementation of print due to the reason that there might be no print -def t_print(*args) - i = 0 - len = args.size - while i < len - str = args[i].to_s - __t_printstr__ str rescue print str - i += 1 +unless RUBY_ENGINE == "mruby" + # For bintest on Ruby + def t_print(*args) + print(*args) + $stdout.flush + nil + end +end + +class Array + def _assertion_join + join("-") + end +end + +class String + def _assertion_indent(indent) + indent = indent.to_s + off = 0 + str = self + while nl = index("\n", off) + nl += 1 + nl += 1 while slice(nl) == "\n" + break if nl >= size + str = indent.dup if off == 0 + str += slice(off, nl - off) + indent + off = nl + end + + if off == 0 + str = indent + self + else + str += slice(off..-1) + end + + str end end @@ -19,16 +49,17 @@ end # Create the assertion in a readable way def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg = "#{err}#{str}" - msg += " [#{iso}]" if iso && iso != '' - msg += " => #{e.cause}" if e && e.respond_to?(:cause) - msg += " => #{e.message}" if e && !e.respond_to?(:cause) - msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME) - if $mrbtest_assert && $mrbtest_assert.size > 0 + msg += " [#{iso}]" if iso && !iso.empty? + msg += " => #{e}" if e && !e.to_s.empty? + msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" + if $mrbtest_assert $mrbtest_assert.each do |idx, assert_msg, diff| - msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" + msg += "\n - Assertion[#{idx}]" + msg += " #{assert_msg}." if assert_msg && !assert_msg.empty? + msg += "\n#{diff}" if diff && !diff.empty? end end - msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt + msg += "\nbacktrace:\n #{bt.join("\n ")}" if bt msg end @@ -43,206 +74,292 @@ end def assert(str = 'Assertion failed', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin + $mrbtest_child_noassert ||= [0] + $mrbtest_child_noassert << 0 + parent_asserts = $asserts + $asserts = [] + parent_mrbtest_assert = $mrbtest_assert $mrbtest_assert = [] - $mrbtest_assert_idx = 0 + + if $mrbtest_assert_idx && !$mrbtest_assert_idx.empty? + $mrbtest_assert_idx[-1] += 1 + $mrbtest_assert_idx << 0 + else + $mrbtest_assert_idx = [0] + class << $mrbtest_assert_idx + alias to_s _assertion_join + end + end + yield - if($mrbtest_assert.size > 0) - $asserts.push(assertion_string('Fail: ', str, iso, nil)) - $ko_test += 1 - t_print('F') + if $mrbtest_assert.size > 0 + if $mrbtest_assert.size == $mrbtest_child_noassert[-1] + $asserts.push(assertion_string('Info: ', str, iso)) + $mrbtest_child_noassert[-2] += 1 + $ok_test += 1 + t_print('.') + else + $asserts.push(assertion_string('Fail: ', str, iso)) + $ko_test += 1 + t_print('F') + end else $ok_test += 1 t_print('.') end + rescue MRubyTestSkip => e + $asserts.push(assertion_string('Skip: ', str, iso, e)) + $skip_test += 1 + $mrbtest_child_noassert[-2] += 1 + t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose - if e.class.to_s == 'MRubyTestSkip' - $asserts.push(assertion_string('Skip: ', str, iso, e, nil)) - t_print('?') + $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt)) + $kill_test += 1 + t_print('X') + ensure + if $mrbtest_assert_idx.size > 1 + $asserts.each do |mesg| + idx = $mrbtest_assert_idx[0..-2]._assertion_join + mesg = mesg._assertion_indent(" ") + + # Give `mesg` as a `diff` argument to avoid adding extra periods. + parent_mrbtest_assert << [idx, nil, mesg] + end else - $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt)) - $kill_test += 1 - t_print('X') + parent_asserts.concat $asserts end - ensure - $mrbtest_assert = nil + $asserts = parent_asserts + + $mrbtest_assert = parent_mrbtest_assert + $mrbtest_assert_idx.pop + $mrbtest_assert_idx = nil if $mrbtest_assert_idx.empty? + $mrbtest_child_noassert.pop + + nil end t_print("\n") if $mrbtest_verbose end def assertion_diff(exp, act) - " Expected: #{exp.inspect}\n" + + " Expected: #{exp.inspect}\n" \ " Actual: #{act.inspect}" end -def assert_true(ret, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 - unless ret - msg = "Expected #{ret.inspect} to be true" unless msg - diff = assertion_diff(true, ret) unless diff - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) +def assert_true(obj, msg = nil, diff = nil) + if $mrbtest_assert_idx && $mrbtest_assert_idx.size > 0 + $mrbtest_assert_idx[-1] += 1 + unless obj == true + diff ||= " Expected #{obj.inspect} to be true." + $mrbtest_assert.push([$mrbtest_assert_idx.to_s, msg, diff]) end end - ret + obj end -def assert_false(ret, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 - if ret - msg = "Expected #{ret.inspect} to be false" unless msg - diff = assertion_diff(false, ret) unless diff +def assert_false(obj, msg = nil, diff = nil) + unless obj == false + diff ||= " Expected #{obj.inspect} to be false." + end + assert_true(!obj, msg, diff) +end + +def assert_equal(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) + unless ret + diff = assertion_diff(exp, act) + end + assert_true(ret, msg, diff) +end - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) +def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) + if ret + diff = " Expected #{act.inspect} to not be equal to #{exp.inspect}." + end + assert_true(!ret, msg, diff) +end + +def assert_same(*args); _assert_same(true, *args) end +def assert_not_same(*args); _assert_same(false, *args) end +def _assert_same(affirmed, exp, act, msg = nil) + unless ret = exp.equal?(act) == affirmed + exp_str, act_str = [exp, act].map do |o| + "#{o.inspect} (class=#{o.class}, oid=#{o.__id__})" end + diff = " Expected #{act_str} to #{'not ' unless affirmed}be the same as #{exp_str}." end - !ret + assert_true(ret, msg, diff) end -def assert_equal(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_nil(obj, msg = nil) + unless ret = obj.nil? + diff = " Expected #{obj.inspect} to be nil." end + assert_true(ret, msg, diff) +end - msg = "Expected to be equal" unless msg - diff = assertion_diff(exp, act) - assert_true(exp == act, msg, diff) +def assert_include(*args); _assert_include(true, *args) end +def assert_not_include(*args); _assert_include(false, *args) end +def _assert_include(affirmed, collection, obj, msg = nil) + unless ret = collection.include?(obj) == affirmed + diff = " Expected #{collection.inspect} to #{'not ' unless affirmed}include #{obj.inspect}." + end + assert_true(ret, msg, diff) end -def assert_not_equal(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_predicate(*args); _assert_predicate(true, *args) end +def assert_not_predicate(*args); _assert_predicate(false, *args) end +def _assert_predicate(affirmed, obj, op, msg = nil) + unless ret = obj.__send__(op) == affirmed + diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}." end + assert_true(ret, msg, diff) +end - msg = "Expected to be not equal" unless msg - diff = assertion_diff(exp, act) - assert_false(exp == act, msg, diff) +def assert_operator(*args); _assert_operator(true, *args) end +def assert_not_operator(*args); _assert_operator(false, *args) end +def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) + return _assert_predicate(affirmed, obj1, op, msg) if $undefined.equal?(obj2) + unless ret = obj1.__send__(op, obj2) == affirmed + diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." + end + assert_true(ret, msg, diff) end -def assert_nil(obj, msg = nil) - msg = "Expected #{obj.inspect} to be nil" unless msg - diff = assertion_diff(nil, obj) - assert_true(obj.nil?, msg, diff) +## +# Fail unless +str+ matches against +pattern+. +# +# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the +# following metacharacters: +# +# <code>*</code> :: +# Matches any string. +# +# <code>?</code> :: +# Matches any one character. +# +# <code>[_SET_]</code>, <code>[^_SET_]</code> (<code>[!_SET_]</code>) :: +# Matches any one character in _SET_. Behaves like character sets in +# Regexp, including set negation (<code>[^a-z]</code>). +# +# <code>{_A_,_B_}</code> :: +# Matches pattern _A_ or pattern _B_. +# +# <code> \ </code> :: +# Escapes the next character. +def assert_match(*args); _assert_match(true, *args) end +def assert_not_match(*args); _assert_match(false, *args) end +def _assert_match(affirmed, pattern, str, msg = nil) + receiver, *args = RUBY_ENGINE == "mruby" ? + [self, :_str_match?, pattern, str] : + [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] + unless ret = !receiver.__send__(*args) == !affirmed + diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." + end + assert_true(ret, msg, diff) end -def assert_include(collection, obj, msg = nil) - msg = "Expected #{collection.inspect} to include #{obj.inspect}" unless msg - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" - assert_true(collection.include?(obj), msg, diff) +## +# Fails unless +obj+ is a kind of +cls+. +def assert_kind_of(cls, obj, msg = nil) + unless ret = obj.kind_of?(cls) + diff = " Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}." + end + assert_true(ret, msg, diff) end -def assert_not_include(collection, obj, msg = nil) - msg = "Expected #{collection.inspect} to not include #{obj.inspect}" unless msg - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" - assert_false(collection.include?(obj), msg, diff) +## +# Fails unless +exp+ is equal to +act+ in terms of a Float +def assert_float(exp, act, msg = nil) + e, a = exp.to_f, act.to_f + if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE + flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + elsif (e.infinite? || a.infinite?) && e != a || + e.nan? && !a.nan? || !e.nan? && a.nan? + flunk(msg, " Expected #{act} to be #{exp}.") + else + pass + end end def assert_raise(*exc) - return true unless $mrbtest_assert - $mrbtest_assert_idx += 1 - msg = (exc.last.is_a? String) ? exc.pop : nil - + exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc begin yield - msg ||= "Expected to raise #{exc} but nothing was raised." - diff = nil - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false rescue *exc - true + pass rescue Exception => e - msg ||= "Expected to raise #{exc}, not" - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false + diff = " #{exc} exception expected, not\n" \ + " Class: <#{e.class}>\n" \ + " Message: <#{e}>" + flunk(msg, diff) + else + diff = " #{exc} expected but nothing was raised." + flunk(msg, diff) end end def assert_nothing_raised(msg = nil) - return true unless $mrbtest_assert - $mrbtest_assert_idx += 1 - begin yield - true rescue Exception => e - msg ||= "Expected not to raise #{exc.join(', ')} but it raised" - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false + diff = " Exception raised:\n" \ + " Class: <#{e.class}>\n" \ + " Message: <#{e}>" + flunk(msg, diff) + else + pass end end -## -# Fails unless +obj+ is a kind of +cls+. -def assert_kind_of(cls, obj, msg = nil) - msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg - diff = assertion_diff(cls, obj.class) - assert_true(obj.kind_of?(cls), msg, diff) +def pass + assert_true(true) end -## -# Fails unless +exp+ is equal to +act+ in terms of a Float -def assert_float(exp, act, msg = nil) - msg = "Float #{exp} expected to be equal to float #{act}" unless msg - diff = assertion_diff(exp, act) - assert_true check_float(exp, act), msg, diff +def flunk(msg = "Epic Fail!", diff = "") + assert_true(false, msg, diff) end ## # Report the test result and print all assertions # which were reported broken. -def report() +def report t_print("\n") $asserts.each do |msg| - t_print "#{msg}\n" + t_print("#{msg}\n") end - $total_test = $ok_test+$ko_test+$kill_test + $total_test = $ok_test + $ko_test + $kill_test + $skip_test t_print("Total: #{$total_test}\n") t_print(" OK: #{$ok_test}\n") t_print(" KO: #{$ko_test}\n") t_print("Crash: #{$kill_test}\n") + t_print(" Skip: #{$skip_test}\n") if Object.const_defined?(:Time) t_time = Time.now - $test_start t_print(" Time: #{t_time.round(2)} seconds\n") end + + $ko_test == 0 && $kill_test == 0 end -## -# Performs fuzzy check for equality on methods returning floats -def check_float(a, b) - tolerance = Mrbtest::FLOAT_TOLERANCE - a = a.to_f - b = b.to_f - if a.finite? and b.finite? - (a-b).abs < tolerance +def _eval_assertion(meth, exp, act_or_msg, msg, block) + if block + exp, act, msg = exp, block.call, act_or_msg else - true + exp, act, msg = exp, act_or_msg, msg end + return exp.__send__(meth, act), exp, act, msg end ## # Skip the test -class MRubyTestSkip < NotImplementedError - attr_accessor :cause - def initialize(cause) - @cause = cause - end -end +class MRubyTestSkip < NotImplementedError; end def skip(cause = "") raise MRubyTestSkip.new(cause) |
