Module: Matchy::Expectations::TestCaseExtensions

Defined in:
lib/matchy/built_in/error_expectations.rb,
lib/matchy/built_in/truth_expectations.rb,
lib/matchy/built_in/change_expectations.rb,
lib/matchy/built_in/enumerable_expectations.rb

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

be_*something(*args)

This method_missing acts as a matcher builder.

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?.

Examples

nil.should be_nil
17.should be_kind_of(Fixnum)
obj.something? #=> true
obj.should be_something


127
128
129
130
131
132
133
# 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

Instance Method Details

#be(*obj) ⇒ Object

Simply checks if the receiver matches the expected object. TODO: Fill this out to implement much of the RSpec functionality (and then some)

Examples

"hello".should be("hello")
(13 < 20).should be(true)


12
13
14
15
16
17
18
19
# 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

#be_close(obj, delta = 0.3) ⇒ Object

Checks if the given object is within a given object and delta.

Examples

(20.0 - 2.0).should be_close(18.0)
(13.0 - 4.0).should be_close(9.0, 0.5)


28
29
30
31
32
33
34
35
# 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

#be_successObject

Asks given for success?(). This is necessary because Rails Integration::Session overides method_missing without grace.

Examples

@response.should be_success


110
111
112
# File 'lib/matchy/built_in/truth_expectations.rb', line 110

def be_success
  ask_for(:success, :with_arg => nil)
end

#change(&block) ⇒ Object

Checks if the given block alters the value of the block attached to change

Examples

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


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 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

#eql(*obj) ⇒ Object

Calls eql? on the given object (i.e., are the objects the same value?)

Examples

1.should_not eql(1.0)
(12 / 6).should eql(6)


55
56
57
# File 'lib/matchy/built_in/truth_expectations.rb', line 55

def eql(*obj)
  ask_for(:eql, :with_arg => obj)
end

#equal(*obj) ⇒ Object

Calls equal? on the given object (i.e., do the two objects have the same object_id?)

Examples

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])


72
73
74
# File 'lib/matchy/built_in/truth_expectations.rb', line 72

def equal(*obj)
  ask_for(:equal, :with_arg => obj)
end

#exclude(*obj) ⇒ Object

Expects the receiver to exclude the given object(s). You can provide multiple arguments to see if all of them are included.

Examples

[1,2,3].should exclude(16)
[7,8,8].should_not exclude(7)
['a', 'b', 'c'].should exclude('e', 'f', 'g')


27
28
29
# File 'lib/matchy/built_in/enumerable_expectations.rb', line 27

def exclude(*obj)
  _clude(:exclude, obj)
end

#existObject

Calls exist? on the given object.

Examples

# found_user.exist?
found_user.should exist


44
45
46
# File 'lib/matchy/built_in/truth_expectations.rb', line 44

def exist
  ask_for(:exist, :with_arg => nil)
end

#include(*obj) ⇒ Object

Calls include? on the receiver for any object. You can also provide multiple arguments to see if all of them are included.

Examples

[1,2,3].should include(1)
[7,8,8].should_not include(3)
['a', 'b', 'c'].should include('a', 'c')


14
15
16
# File 'lib/matchy/built_in/enumerable_expectations.rb', line 14

def include(*obj)
  _clude(:include, obj)
end

#old_missingObject



114
# File 'lib/matchy/built_in/truth_expectations.rb', line 114

alias_method :old_missing, :method_missing

#raise_error(*obj) ⇒ Object

Expects a lambda to raise an error. You can specify the error or leave it blank to encompass any error.

Examples

lambda { raise "FAILURE." }.should raise_error
lambda { puts i_dont_exist }.should raise_error(NameError)


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 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
    if args.size > 1
      expected_message = args[1]
    end
    
    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
      expected_message = expected
    end
    
    if expected_message
      message = error ? error.message : "none"
      matcher.positive_failure_message = "Expected #{receiver.inspect} to raise error with message matching '#{expected_message}', but '#{message}' was raised."
      matcher.negative_failure_message = "Expected #{receiver.inspect} to raise error with message not matching '#{expected_message}', but '#{message}' was raised."
      comparison = (raised && (expected_message.kind_of?(Regexp) ? ((error.message =~ expected_message) ? true : false) : expected_message == error.message))
    end
    comparison
  end
end

#respond_to(*meth) ⇒ Object

Checks if the given object responds to the given method

Examples

"foo".should respond_to(:length)
{}.should respond_to(:has_key?)


99
100
101
# File 'lib/matchy/built_in/truth_expectations.rb', line 99

def respond_to(*meth)
  ask_for(:respond_to, :with_arg => meth)
end

#satisfy(*obj) ⇒ Object

A last ditch way to implement your testing logic. You probably shouldn’t use this unless you have to.

Examples

(13 - 4).should satisfy(lambda {|i| i < 20})
"hello".should_not satisfy(lambda {|s| s =~ /hi/})


84
85
86
87
88
89
90
91
# 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

#throw_symbol(*obj) ⇒ Object

Expects a lambda to throw an error.

Examples

lambda { throw :thing }.should throw_symbol(:thing)
lambda { "not this time" }.should_not throw_symbol(:hello)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/matchy/built_in/error_expectations.rb', line 53

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