lib/pork.rb in pork-0.9.0 vs lib/pork.rb in pork-0.9.1
- old
+ new
@@ -1,11 +1,11 @@
require 'thread'
module Kernel
- def should message=nil, &checker
- Pork::Should.new(self, message, &checker)
+ def should message=nil, message_lazy=nil, &checker
+ Pork::Should.new(self, message, message_lazy, &checker)
end
end
module Pork
Error = Class.new(Exception)
@@ -17,14 +17,62 @@
def self.report; stats.report; reset ; end
def self.report_at_exit
Pork.stats.start
@report_at_exit ||= at_exit do
stats.report
- exit stats.failures.size + stats.errors.size
+ exit stats.failures.size + stats.errors.size + ($! && 1).to_i
end
end
+ # default to :auto while eliminating warnings for uninitialized ivar
+ def self.inspect_failure_mode mode=nil; @mode = mode || @mode ||= :auto; end
+ def self.inspect_failure *args
+ lambda{ public_send("inspect_failure_#{inspect_failure_mode}", *args) }
+ end
+ def self.inspect_failure_auto object, msg, args, negate
+ if args.size > 1
+ inspect_failure_inline(object, msg, args, negate)
+ elsif object.kind_of?(Hash) && args.first.kind_of?(Hash)
+ inspect_failure_inline(Hash[object.sort], msg,
+ [Hash[args.first.sort]], negate)
+ elsif object.kind_of?(String) && object.size > 400 &&
+ object.count("\n") > 4 && !`which diff`.empty?
+ inspect_failure_diff(object, msg, args, negate)
+ else
+ ins = object.inspect
+ if ins.size > 78
+ inspect_failure_newline(object, msg, args, negate)
+ else
+ inspect_failure_inline( object, msg, args, negate)
+ end
+ end
+ end
+
+ def self.inspect_failure_inline object, msg, args, negate
+ a = args.map(&:inspect).join(', ')
+ "#{object.inspect}.#{msg}(#{a}) to return #{!negate}"
+ end
+
+ def self.inspect_failure_newline object, msg, args, negate
+ a = args.map(&:inspect).join(",\n")
+ "\n#{object.inspect}.#{msg}(\n#{a}) to return #{!negate}"
+ end
+
+ def self.inspect_failure_diff object, msg, args, negate
+ require 'tempfile'
+ Tempfile.open('pork-expect') do |expect|
+ Tempfile.open('pork-was') do |was|
+ expect.puts(object.to_s)
+ expect.close
+ was.puts(args.map(&:to_s).join(",\n"))
+ was.close
+ name = "#{object.class}##{msg}(\n"
+ "#{name}#{`diff #{expect.path} #{was.path}`}) to return #{!negate}"
+ end
+ end
+ end
+
module API
module_function
def before █ Executor.before(&block); end
def after █ Executor.after( &block); end
def describe desc=:default, &suite; Executor.describe(desc, &suite); end
@@ -44,12 +92,11 @@
def describe desc=:default, &suite
Class.new(self){ init("#{desc}: ") }.module_eval(&suite)
end
def copy desc=:default, &suite; stash[desc] = suite; end
def paste desc=:default, *args
- stashes = [self, super_executor].compact.map(&:stash)
- module_exec(*args, &stashes.find{ |s| s[desc] }[desc])
+ module_exec(*args, &search_stash(desc))
end
def would desc=:default, &test
assertions = Pork.stats.assertions
context = new(desc)
run_before(context)
@@ -72,25 +119,26 @@
Pork.stats.incr_tests
run_after(context)
end
protected
- def init desc=''
- @desc, @before, @after, @stash = desc, [], [], {}
- end
+ def init desc=''; @desc, @before, @after, @stash = desc, [], [], {}; end
def super_executor
@super_executor ||= ancestors[1..-1].find{ |a| a <= Executor }
end
+ def search_stash desc
+ stash[desc] or super_executor && super_executor.search_stash(desc)
+ end
def description_for name=''
"#{desc}#{super_executor && super_executor.description_for}#{name}"
end
def run_before context
- super_executor.run_before(context) if super_executor
+ super_executor && super_executor.run_before(context)
before.each{ |b| context.instance_eval(&b) }
end
def run_after context
- super_executor.run_after(context) if super_executor
+ super_executor && super_executor.run_after(context)
after.each{ |b| context.instance_eval(&b) }
end
end
class Executor < Struct.new(:desc)
@@ -99,62 +147,30 @@
def skip ; raise Skip.new("Skipping #{desc}"); end
def flunk reason='Flunked'; raise Error.new(reason) ; end
def ok ; Pork.stats.incr_assertions ; end
end
- module InspectInlineError
- def inspect_error object, msg, args, negate
- a = args.map(&:inspect).join(', ')
- "#{object.inspect}.#{msg}(#{a}) to return #{!negate}"
- end
- end
-
- module InspectNewlineError
- def inspect_error object, msg, args, negate
- a = args.map(&:inspect).join(', ')
- "\n#{object.inspect}.#{msg}(\n#{a}) to return #{!negate}"
- end
- end
-
- module InspectDiffError
- def inspect_error object, msg, args, negate
- ::Kernel.require 'tempfile'
- ::Tempfile.open('pork-expect') do |expect|
- ::Tempfile.open('pork-was') do |was|
- expect.puts(object.to_s)
- expect.close
- was.puts(args.map(&:to_s).join(",\n"))
- was.close
- name = "#{object.class}##{msg}(\n"
- diff = ::Kernel.__send__(:`, "diff #{expect.path} #{was.path}")
- "#{name}#{diff}) to return #{!negate}"
- end
- end
- end
- end
-
class Should < BasicObject
instance_methods.each{ |m| undef_method(m) unless m =~ /^__|^object_id$/ }
- include ::Pork::InspectInlineError
-
- def initialize object, message, &checker
- @object = object
- @negate = false
- @message = message
+ def initialize object, message=nil, message_lazy=nil, &checker
+ @object, @negate = object, false
+ @message, @message_lazy = message, message_lazy
satisfy(&checker) if checker
end
def method_missing msg, *args, &block
- satisfy(inspect_error(@object, msg, args, @negate)) do
+ satisfy(nil, ::Pork.inspect_failure(@object, msg, args, @negate)) do
@object.public_send(msg, *args, &block)
end
end
- def satisfy desc=@object
+ def satisfy desc=@object, desc_lazy=nil
result = yield(@object)
if !!result == @negate
- ::Kernel.raise Failure.new("Expect #{desc}\n#{@message}".chomp)
+ d = desc_lazy && desc_lazy.call || desc
+ m = @message_lazy && @message_lazy.call || @message
+ ::Kernel.raise Failure.new("Expect #{d}\n#{m}".chomp)
else
::Pork.stats.incr_assertions
end
result
end
@@ -193,17 +209,11 @@
flag && [msg, data]
end
end
private
- def __not__
- if @negate == true
- 'not '
- else
- ''
- end
- end
+ def __not__; if @negate == true then 'not ' else '' end; end
end
class Stats < Struct.new(:tests, :assertions, :skips, :failures, :errors)
def initialize
@mutex = Mutex.new
@@ -212,15 +222,11 @@
def incr_assertions; @mutex.synchronize{ self.assertions += 1 }; end
def incr_tests ; @mutex.synchronize{ self.tests += 1 }; end
def incr_skips ; @mutex.synchronize{ self.skips += 1; print('s')}; end
def add_failure *e ; @mutex.synchronize{ failures << e; print('F')}; end
def add_error *e ; @mutex.synchronize{ errors << e; print('E')}; end
- def numbers
- [tests, assertions, failures.size, errors.size, skips]
- end
- def start
- @start ||= Time.now
- end
+ def numbers; [tests, assertions, failures.size, errors.size, skips]; end
+ def start ; @start ||= Time.now ; end
def report
puts
puts (failures + errors).map{ |(e, m)|
"\n#{m}\n#{e.class}: #{e.message}\n #{backtrace(e)}"
}