Simply checks if the receiver matches the expected object. TODO: Fill this out to implement much of the RSpec functionality (and then some)
"hello".should be("hello") (13 < 20).should be(true)
# File lib/matchy/built_in/truth_expectations.rb, line 12 def be(*obj) build_matcher(:be, obj) do |receiver, matcher, args| @receiver, expected = receiver, args[0] matcher.positive_failure_message = "Expected #{@receiver.inspect} to be #{expected.inspect}." matcher.negative_failure_message = "Expected #{@receiver.inspect} to not be #{expected.inspect}." expected == @receiver end end
Checks if the given object is within a given object and delta.
(20.0 - 2.0).should be_close(18.0) (13.0 - 4.0).should be_close(9.0, 0.5)
# File lib/matchy/built_in/truth_expectations.rb, line 28 def be_close(obj, delta = 0.3) build_matcher(:be_close, [obj, delta]) do |receiver, matcher, args| @receiver, expected, delta = receiver, args[0], args[1] matcher.positive_failure_message = "Expected #{@receiver.inspect} to be close to #{expected.inspect} (delta: #{delta})." matcher.negative_failure_message = "Expected #{@receiver.inspect} to not be close to #{expected.inspect} (delta: #{delta})." (@receiver - expected).abs < delta end end
Asks given for success?(). This is necessary because Rails Integration::Session overides #method_missing without grace.
@response.should be_success
# File lib/matchy/built_in/truth_expectations.rb, line 110 def be_success ask_for(:success, :with_arg => nil) end
Checks if the given block alters the value of the block attached to change
lambda {var += 1}.should change {var}.by(1) lambda {var += 2}.should change {var}.by_at_least(1) lambda {var += 1}.should change {var}.by_at_most(1) lambda {var += 2}.should change {var}.from(1).to(3) if var = 1
# File lib/matchy/built_in/change_expectations.rb, line 11 def change(&block) build_matcher(:change) do |receiver, matcher, args| before, done, after = block.call, receiver.call, block.call comparison = after != before if list = matcher.chained_messages comparison = case list[0].name # todo: provide meaningful messages when :by then (after == before + list[0].args[0] || after == before - list[0].args[0]) when :by_at_least then (after >= before + list[0].args[0] || after <= before - list[0].args[0]) when :by_at_most then (after <= before + list[0].args[0] && after >= before - list[0].args[0]) when :from then (before == list[0].args[0]) && (after == list[1].args[0]) end end matcher.positive_failure_message = "given block shouldn't alter the block attached to change" matcher.negative_failure_message = "given block should alter the block attached to change" comparison end end
Calls equal?
on the given object (i.e., do the two objects
have the same object_id
?)
x = [1,2,3] y = [1,2,3] # Different object_id's... x.should_not equal(y) # The same object_id x[0].should equal(y[0])
# File lib/matchy/built_in/truth_expectations.rb, line 72 def equal(*obj) ask_for(:equal, :with_arg => obj) end
Expects the receiver to exclude the given object(s). You can provide multiple arguments to see if all of them are included.
[1,2,3].should exclude(16) [7,8,8].should_not exclude(7) ['a', 'b', 'c'].should exclude('e', 'f', 'g')
# File lib/matchy/built_in/enumerable_expectations.rb, line 27 def exclude(*obj) _clude(:exclude, obj) end
Calls include?
on the receiver for any object. You can also
provide multiple arguments to see if all of them are included.
[1,2,3].should include(1) [7,8,8].should_not include(3) ['a', 'b', 'c'].should include('a', 'c')
# File lib/matchy/built_in/enumerable_expectations.rb, line 14 def include(*obj) _clude(:include, obj) end
If a call to be_xyz() reaches this #method_missing (say: obj.should be_xyz), a matcher with the name xyz will be built, whose defining property is that it returns the value of obj.xyz? for matches?.
nil.should be_nil 17.should be_kind_of(Fixnum) obj.something? #=> true obj.should be_something
# File lib/matchy/built_in/truth_expectations.rb, line 127 def method_missing(name, *args, &block) if (name.to_s =~ /^be_(.+)/) ask_for($1, :with_arg => args) else old_missing(name, *args, &block) end end
Expects a lambda to raise an error. You can specify the error or leave it blank to encompass any error.
lambda { raise "FAILURE." }.should raise_error lambda { puts i_dont_exist }.should raise_error(NameError)
# File lib/matchy/built_in/error_expectations.rb, line 12 def raise_error(*obj) build_matcher(:raise_error, obj) do |receiver, matcher, args| expected = args[0] || Exception raised = false error = nil begin receiver.call rescue Exception => e raised = true error = e end if expected.respond_to?(:ancestors) && expected.ancestors.include?(Exception) matcher.positive_failure_message = "Expected #{receiver.inspect} to raise #{expected.name}, " + (error ? "but #{error.class.name} was raised instead." : "but none was raised.") matcher.negative_failure_message = "Expected #{receiver.inspect} to not raise #{expected.name}." comparison = (raised && error.class.ancestors.include?(expected)) else message = error ? error.message : "none" matcher.positive_failure_message = "Expected #{receiver.inspect} to raise error with message matching '#{expected}', but '#{message}' was raised." matcher.negative_failure_message = "Expected #{receiver.inspect} to raise error with message not matching '#{expected}', but '#{message}' was raised." comparison = (raised && (expected.kind_of?(Regexp) ? ((error.message =~ expected) ? true : false) : expected == error.message)) end comparison end end
A last ditch way to implement your testing logic. You probably shouldn't use this unless you have to.
(13 - 4).should satisfy(lambda {|i| i < 20}) "hello".should_not satisfy(lambda {|s| s =~ /hi/})
# File lib/matchy/built_in/truth_expectations.rb, line 84 def satisfy(*obj) build_matcher(:satisfy, obj) do |receiver, matcher, args| @receiver, expected = receiver, args[0] matcher.positive_failure_message = "Expected #{@receiver.inspect} to satisfy given block." matcher.negative_failure_message = "Expected #{@receiver.inspect} to not satisfy given block." expected.call(@receiver) == true end end
Expects a lambda to throw an error.
lambda { throw :thing }.should throw_symbol(:thing) lambda { "not this time" }.should_not throw_symbol(:hello)
# File lib/matchy/built_in/error_expectations.rb, line 45 def throw_symbol(*obj) build_matcher(:throw_symbol, obj) do |receiver, matcher, args| raised, thrown_symbol, expected = false, nil, args[0] begin receiver.call rescue NameError => e raise e unless e.message =~ /uncaught throw/ raised = true thrown_symbol = e.name.to_sym if e.respond_to?(:name) rescue ArgumentError => e raise e unless e.message =~ /uncaught throw/ thrown_symbol = e.message.match(/uncaught throw :(.+)/)[1].to_sym end matcher.positive_failure_message = "Expected #{receiver.inspect} to throw :#{expected}, but " + "#{thrown_symbol ? ':' + thrown_symbol.to_s + ' was thrown instead' : 'no symbol was thrown'}." matcher.negative_failure_message = "Expected #{receiver.inspect} to not throw :#{expected}." expected == thrown_symbol end end
# File lib/matchy/built_in/enumerable_expectations.rb, line 32 def _clude(sym, obj) build_matcher(sym, obj) do |given, matcher, args| matcher.positive_failure_message = "Expected #{given.inspect} to #{sym} #{args.inspect}." matcher.negative_failure_message = "Expected #{given.inspect} to not #{sym} #{args.inspect}." args.inject(true) {|m,o| m && (given.include?(o) == (sym == :include)) } end end
# File lib/matchy/built_in/truth_expectations.rb, line 136 def ask_for(sym, option={}) build_matcher(sym, (option[:with_arg] || [])) do |receiver, matcher, args| expected, meth = args[0], (sym.to_s + "?" ).to_sym matcher.positive_failure_message = "Expected #{receiver.inspect} to return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'." matcher.negative_failure_message = "Expected #{receiver.inspect} to not return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'." expected ? receiver.send(meth, expected) : receiver.send(meth) end end