jnunemaker-matchy 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +36 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +162 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +15 -0
- data/countloc.rb +67 -0
- data/lib/matchy.rb +19 -0
- data/lib/matchy/built_in/change_expectations.rb +31 -0
- data/lib/matchy/built_in/enumerable_expectations.rb +41 -0
- data/lib/matchy/built_in/error_expectations.rb +66 -0
- data/lib/matchy/built_in/operator_expectations.rb +42 -0
- data/lib/matchy/built_in/truth_expectations.rb +146 -0
- data/lib/matchy/custom_matcher.rb +10 -0
- data/lib/matchy/expectation_builder.rb +9 -0
- data/lib/matchy/matcher_builder.rb +51 -0
- data/lib/matchy/modals.rb +34 -0
- data/lib/matchy/version.rb +9 -0
- data/matchy.gemspec +26 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/test/all.rb +7 -0
- data/test/ruby1.9.compatibility_tests.rb +541 -0
- data/test/test_change_expectation.rb +63 -0
- data/test/test_custom_matcher.rb +139 -0
- data/test/test_enumerable_expectations.rb +91 -0
- data/test/test_error_expectations.rb +144 -0
- data/test/test_expectation_builder.rb +28 -0
- data/test/test_helper.rb +1 -0
- data/test/test_matcher_builder.rb +72 -0
- data/test/test_modals.rb +39 -0
- data/test/test_operator_expectations.rb +157 -0
- data/test/test_truth_expectations.rb +373 -0
- metadata +109 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Matchy
|
2
|
+
module Expectations
|
3
|
+
module TestCaseExtensions
|
4
|
+
|
5
|
+
# Calls +include?+ on the receiver for any object. You can also provide
|
6
|
+
# multiple arguments to see if all of them are included.
|
7
|
+
#
|
8
|
+
# ==== Examples
|
9
|
+
#
|
10
|
+
# [1,2,3].should include(1)
|
11
|
+
# [7,8,8].should_not include(3)
|
12
|
+
# ['a', 'b', 'c'].should include('a', 'c')
|
13
|
+
#
|
14
|
+
def include(*obj)
|
15
|
+
_clude(:include, obj)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Expects the receiver to exclude the given object(s). You can provide
|
19
|
+
# multiple arguments to see if all of them are included.
|
20
|
+
#
|
21
|
+
# ==== Examples
|
22
|
+
#
|
23
|
+
# [1,2,3].should exclude(16)
|
24
|
+
# [7,8,8].should_not exclude(7)
|
25
|
+
# ['a', 'b', 'c'].should exclude('e', 'f', 'g')
|
26
|
+
#
|
27
|
+
def exclude(*obj)
|
28
|
+
_clude(:exclude, obj)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def _clude(sym, obj)
|
33
|
+
build_matcher(sym, obj) do |given, matcher, args|
|
34
|
+
matcher.positive_failure_message = "Expected #{given.inspect} to #{sym} #{args.inspect}."
|
35
|
+
matcher.negative_failure_message = "Expected #{given.inspect} to not #{sym} #{args.inspect}."
|
36
|
+
args.inject(true) {|m,o| m && (given.include?(o) == (sym == :include)) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Matchy
|
2
|
+
module Expectations
|
3
|
+
module TestCaseExtensions
|
4
|
+
# Expects a lambda to raise an error. You can specify the error or leave it blank to encompass
|
5
|
+
# any error.
|
6
|
+
#
|
7
|
+
# ==== Examples
|
8
|
+
#
|
9
|
+
# lambda { raise "FAILURE." }.should raise_error
|
10
|
+
# lambda { puts i_dont_exist }.should raise_error(NameError)
|
11
|
+
#
|
12
|
+
def raise_error(*obj)
|
13
|
+
build_matcher(:raise_error, obj) do |receiver, matcher, args|
|
14
|
+
expected = args[0] || Exception
|
15
|
+
raised = false
|
16
|
+
error = nil
|
17
|
+
begin
|
18
|
+
receiver.call
|
19
|
+
rescue Exception => e
|
20
|
+
raised = true
|
21
|
+
error = e
|
22
|
+
end
|
23
|
+
if expected.respond_to?(:ancestors) && expected.ancestors.include?(Exception)
|
24
|
+
matcher.positive_failure_message = "Expected #{receiver.inspect} to raise #{expected.name}, " +
|
25
|
+
(error ? "but #{error.class.name} was raised instead." : "but none was raised.")
|
26
|
+
matcher.negative_failure_message = "Expected #{receiver.inspect} to not raise #{expected.name}."
|
27
|
+
comparison = (raised && error.class.ancestors.include?(expected))
|
28
|
+
else
|
29
|
+
message = error ? error.message : "none"
|
30
|
+
matcher.positive_failure_message = "Expected #{receiver.inspect} to raise error with message matching '#{expected}', but '#{message}' was raised."
|
31
|
+
matcher.negative_failure_message = "Expected #{receiver.inspect} to raise error with message not matching '#{expected}', but '#{message}' was raised."
|
32
|
+
comparison = (raised && (expected.kind_of?(Regexp) ? ((error.message =~ expected) ? true : false) : expected == error.message))
|
33
|
+
end
|
34
|
+
comparison
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Expects a lambda to throw an error.
|
39
|
+
#
|
40
|
+
# ==== Examples
|
41
|
+
#
|
42
|
+
# lambda { throw :thing }.should throw_symbol(:thing)
|
43
|
+
# lambda { "not this time" }.should_not throw_symbol(:hello)
|
44
|
+
#
|
45
|
+
def throw_symbol(*obj)
|
46
|
+
build_matcher(:throw_symbol, obj) do |receiver, matcher, args|
|
47
|
+
raised, thrown_symbol, expected = false, nil, args[0]
|
48
|
+
begin
|
49
|
+
receiver.call
|
50
|
+
rescue NameError => e
|
51
|
+
raise e unless e.message =~ /uncaught throw/
|
52
|
+
raised = true
|
53
|
+
thrown_symbol = e.name.to_sym if e.respond_to?(:name)
|
54
|
+
rescue ArgumentError => e
|
55
|
+
raise e unless e.message =~ /uncaught throw/
|
56
|
+
thrown_symbol = e.message.match(/uncaught throw :(.+)/)[1].to_sym
|
57
|
+
end
|
58
|
+
matcher.positive_failure_message = "Expected #{receiver.inspect} to throw :#{expected}, but " +
|
59
|
+
"#{thrown_symbol ? ':' + thrown_symbol.to_s + ' was thrown instead' : 'no symbol was thrown'}."
|
60
|
+
matcher.negative_failure_message = "Expected #{receiver.inspect} to not throw :#{expected}."
|
61
|
+
expected == thrown_symbol
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Matchy
|
2
|
+
module Expectations
|
3
|
+
# Class to handle operator expectations.
|
4
|
+
#
|
5
|
+
# ==== Examples
|
6
|
+
#
|
7
|
+
# 13.should == 13
|
8
|
+
# "hello".length.should_not == 2
|
9
|
+
#
|
10
|
+
class OperatorExpectation #< Base
|
11
|
+
include Test::Unit::Assertions
|
12
|
+
|
13
|
+
def initialize(receiver, match)
|
14
|
+
@receiver, @match = receiver, match
|
15
|
+
end
|
16
|
+
|
17
|
+
['==', '===', '=~', '>', '>=', '<', '<='].each do |op|
|
18
|
+
define_method(op) do |expected|
|
19
|
+
@expected = expected
|
20
|
+
(@receiver.send(op,expected) ? true : false) == @match ? pass! : fail!(op)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
def pass!
|
26
|
+
defined?($current_test_case) ? $current_test_case.assert(true) : (assert true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def fail!(operator)
|
30
|
+
flunk @match ? failure_message(operator) : negative_failure_message(operator)
|
31
|
+
end
|
32
|
+
|
33
|
+
def failure_message(operator)
|
34
|
+
"Expected #{@receiver.inspect} to #{operator} #{@expected.inspect}."
|
35
|
+
end
|
36
|
+
|
37
|
+
def negative_failure_message(operator)
|
38
|
+
"Expected #{@receiver.inspect} to not #{operator} #{@expected.inspect}."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module Matchy
|
2
|
+
module Expectations
|
3
|
+
module TestCaseExtensions
|
4
|
+
# Simply checks if the receiver matches the expected object.
|
5
|
+
# TODO: Fill this out to implement much of the RSpec functionality (and then some)
|
6
|
+
#
|
7
|
+
# ==== Examples
|
8
|
+
#
|
9
|
+
# "hello".should be("hello")
|
10
|
+
# (13 < 20).should be(true)
|
11
|
+
#
|
12
|
+
def be(*obj)
|
13
|
+
build_matcher(:be, obj) do |receiver, matcher, args|
|
14
|
+
@receiver, expected = receiver, args[0]
|
15
|
+
matcher.positive_failure_message = "Expected #{@receiver.inspect} to be #{expected.inspect}."
|
16
|
+
matcher.negative_failure_message = "Expected #{@receiver.inspect} to not be #{expected.inspect}."
|
17
|
+
expected == @receiver
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Checks if the given object is within a given object and delta.
|
22
|
+
#
|
23
|
+
# ==== Examples
|
24
|
+
#
|
25
|
+
# (20.0 - 2.0).should be_close(18.0)
|
26
|
+
# (13.0 - 4.0).should be_close(9.0, 0.5)
|
27
|
+
#
|
28
|
+
def be_close(obj, delta = 0.3)
|
29
|
+
build_matcher(:be_close, [obj, delta]) do |receiver, matcher, args|
|
30
|
+
@receiver, expected, delta = receiver, args[0], args[1]
|
31
|
+
matcher.positive_failure_message = "Expected #{@receiver.inspect} to be close to #{expected.inspect} (delta: #{delta})."
|
32
|
+
matcher.negative_failure_message = "Expected #{@receiver.inspect} to not be close to #{expected.inspect} (delta: #{delta})."
|
33
|
+
(@receiver - expected).abs < delta
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Calls +exist?+ on the given object.
|
38
|
+
#
|
39
|
+
# ==== Examples
|
40
|
+
#
|
41
|
+
# # found_user.exist?
|
42
|
+
# found_user.should exist
|
43
|
+
#
|
44
|
+
def exist
|
45
|
+
ask_for(:exist, :with_arg => nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Calls +eql?+ on the given object (i.e., are the objects the same value?)
|
49
|
+
#
|
50
|
+
# ==== Examples
|
51
|
+
#
|
52
|
+
# 1.should_not eql(1.0)
|
53
|
+
# (12 / 6).should eql(6)
|
54
|
+
#
|
55
|
+
def eql(*obj)
|
56
|
+
ask_for(:eql, :with_arg => obj)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Calls +equal?+ on the given object (i.e., do the two objects have the same +object_id+?)
|
60
|
+
#
|
61
|
+
# ==== Examples
|
62
|
+
#
|
63
|
+
# x = [1,2,3]
|
64
|
+
# y = [1,2,3]
|
65
|
+
#
|
66
|
+
# # Different object_id's...
|
67
|
+
# x.should_not equal(y)
|
68
|
+
#
|
69
|
+
# # The same object_id
|
70
|
+
# x[0].should equal(y[0])
|
71
|
+
#
|
72
|
+
def equal(*obj)
|
73
|
+
ask_for(:equal, :with_arg => obj)
|
74
|
+
end
|
75
|
+
|
76
|
+
# A last ditch way to implement your testing logic. You probably shouldn't use this unless you
|
77
|
+
# have to.
|
78
|
+
#
|
79
|
+
# ==== Examples
|
80
|
+
#
|
81
|
+
# (13 - 4).should satisfy(lambda {|i| i < 20})
|
82
|
+
# "hello".should_not satisfy(lambda {|s| s =~ /hi/})
|
83
|
+
#
|
84
|
+
def satisfy(*obj)
|
85
|
+
build_matcher(:satisfy, obj) do |receiver, matcher, args|
|
86
|
+
@receiver, expected = receiver, args[0]
|
87
|
+
matcher.positive_failure_message = "Expected #{@receiver.inspect} to satisfy given block."
|
88
|
+
matcher.negative_failure_message = "Expected #{@receiver.inspect} to not satisfy given block."
|
89
|
+
expected.call(@receiver) == true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Checks if the given object responds to the given method
|
94
|
+
#
|
95
|
+
# ==== Examples
|
96
|
+
#
|
97
|
+
# "foo".should respond_to(:length)
|
98
|
+
# {}.should respond_to(:has_key?)
|
99
|
+
def respond_to(*meth)
|
100
|
+
ask_for(:respond_to, :with_arg => meth)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Asks given for success?().
|
104
|
+
# This is necessary because Rails Integration::Session
|
105
|
+
# overides method_missing without grace.
|
106
|
+
#
|
107
|
+
# ==== Examples
|
108
|
+
#
|
109
|
+
# @response.should be_success
|
110
|
+
def be_success
|
111
|
+
ask_for(:success, :with_arg => nil)
|
112
|
+
end
|
113
|
+
|
114
|
+
alias_method :old_missing, :method_missing
|
115
|
+
# ==be_*something(*args)
|
116
|
+
#
|
117
|
+
# ===This method_missing acts as a matcher builder.
|
118
|
+
# If a call to be_xyz() reaches this method_missing (say: obj.should be_xyz),
|
119
|
+
# a matcher with the name xyz will be built, whose defining property
|
120
|
+
# is that it returns the value of obj.xyz? for matches?.
|
121
|
+
# ==== Examples
|
122
|
+
#
|
123
|
+
# nil.should be_nil
|
124
|
+
# 17.should be_kind_of(Fixnum)
|
125
|
+
# obj.something? #=> true
|
126
|
+
# obj.should be_something
|
127
|
+
def method_missing(name, *args, &block)
|
128
|
+
if (name.to_s =~ /^be_(.+)/)
|
129
|
+
ask_for($1, :with_arg => args)
|
130
|
+
else
|
131
|
+
old_missing(name, *args, &block)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def ask_for(sym, option={})
|
137
|
+
build_matcher(sym, (option[:with_arg] || [])) do |receiver, matcher, args|
|
138
|
+
expected, meth = args[0], (sym.to_s + "?" ).to_sym
|
139
|
+
matcher.positive_failure_message = "Expected #{receiver.inspect} to return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
|
140
|
+
matcher.negative_failure_message = "Expected #{receiver.inspect} to not return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
|
141
|
+
expected ? receiver.send(meth, expected) : receiver.send(meth)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Matchy
|
2
|
+
module MatcherBuilder
|
3
|
+
class ChainedMessage < Struct.new(:name, :args, :block); end
|
4
|
+
|
5
|
+
def build_matcher(matcher_name=nil, args=[], &block)
|
6
|
+
match_block = lambda do |actual, matcher|
|
7
|
+
block.call(actual, matcher, args)
|
8
|
+
end
|
9
|
+
|
10
|
+
body = lambda do |klass|
|
11
|
+
include Test::Unit::Assertions
|
12
|
+
@matcher_name = matcher_name.to_s
|
13
|
+
|
14
|
+
def self.matcher_name
|
15
|
+
@matcher_name
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :matcher_name
|
19
|
+
attr_accessor :positive_failure_message, :negative_failure_message, :chained_messages
|
20
|
+
|
21
|
+
def initialize(match_block, test_case)
|
22
|
+
@match_block, @test_case = match_block, test_case
|
23
|
+
@matcher_name = self.class.matcher_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(id, *args, &block)
|
27
|
+
(self.chained_messages ||= []) << ChainedMessage.new(id, args, block)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches?(given)
|
32
|
+
@positive_failure_message ||= "Matching with '#{matcher_name}' failed, although it should match."
|
33
|
+
@negative_failure_message ||= "Matching with '#{matcher_name}' passed, although it should_not match."
|
34
|
+
@match_block.call(given, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def fail!(which)
|
38
|
+
@test_case.flunk(which ? failure_message : negative_failure_message)
|
39
|
+
end
|
40
|
+
|
41
|
+
def pass!(which)
|
42
|
+
@test_case.assert true
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :failure_message, :positive_failure_message
|
46
|
+
end
|
47
|
+
|
48
|
+
Class.new(&body).new(match_block, self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Matchy
|
2
|
+
module Modals
|
3
|
+
# Tests an expectation against the given object.
|
4
|
+
#
|
5
|
+
# ==== Examples
|
6
|
+
#
|
7
|
+
# "hello".should eql("hello")
|
8
|
+
# 13.should equal(13)
|
9
|
+
# lambda { raise "u r doomed" }.should raise_error
|
10
|
+
#
|
11
|
+
def should(expectation = nil)
|
12
|
+
Matchy::ExpectationBuilder.build_expectation(true, expectation, self)
|
13
|
+
end
|
14
|
+
|
15
|
+
alias :will :should
|
16
|
+
|
17
|
+
# Tests that an expectation doesn't match the given object.
|
18
|
+
#
|
19
|
+
# ==== Examples
|
20
|
+
#
|
21
|
+
# "hello".should_not eql("hi")
|
22
|
+
# 41.should_not equal(13)
|
23
|
+
# lambda { "savd bai da bell" }.should_not raise_error
|
24
|
+
#
|
25
|
+
def should_not(expectation = nil)
|
26
|
+
Matchy::ExpectationBuilder.build_expectation(false, expectation, self)
|
27
|
+
end
|
28
|
+
|
29
|
+
alias :will_not :should_not
|
30
|
+
alias :wont :should_not
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Object.send(:include, Matchy::Modals)
|
data/matchy.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{jnunemaker-matchy}
|
3
|
+
s.version = "0.4.0"
|
4
|
+
s.authors = ["Jeremy McAnally"]
|
5
|
+
s.date = %q{2009-03-23}
|
6
|
+
s.description = %q{RSpec-esque matchers for use in Test::Unit}
|
7
|
+
s.email = ["jeremy@entp.com"]
|
8
|
+
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
|
9
|
+
s.files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "config/hoe.rb", "config/requirements.rb", "countloc.rb", "lib/matchy.rb", "lib/matchy/built_in/change_expectations.rb", "lib/matchy/built_in/enumerable_expectations.rb", "lib/matchy/built_in/error_expectations.rb", "lib/matchy/built_in/operator_expectations.rb", "lib/matchy/built_in/truth_expectations.rb", "lib/matchy/custom_matcher.rb", "lib/matchy/expectation_builder.rb", "lib/matchy/matcher_builder.rb", "lib/matchy/modals.rb", "lib/matchy/version.rb", "matchy.gemspec", "setup.rb", "tasks/deployment.rake", "tasks/environment.rake", "test/all.rb", "test/ruby1.9.compatibility_tests.rb", "test/test_change_expectation.rb", "test/test_custom_matcher.rb", "test/test_enumerable_expectations.rb", "test/test_error_expectations.rb", "test/test_expectation_builder.rb", "test/test_helper.rb", "test/test_matcher_builder.rb", "test/test_modals.rb", "test/test_operator_expectations.rb", "test/test_truth_expectations.rb"]
|
10
|
+
s.has_rdoc = true
|
11
|
+
s.homepage = %q{http://matchy.rubyforge.org}
|
12
|
+
s.post_install_message = %q{
|
13
|
+
For more information on matchy, see http://matchy.rubyforge.org
|
14
|
+
|
15
|
+
NOTE: Change this information in PostInstall.txt
|
16
|
+
You can also delete it if you don't want it.
|
17
|
+
|
18
|
+
}
|
19
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
20
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.rubyforge_project = %q{matchy}
|
23
|
+
s.rubygems_version = %q{1.3.1}
|
24
|
+
s.summary = %q{RSpec-esque matchers for use in Test::Unit}
|
25
|
+
s.test_files = ["test/test_change_expectation.rb", "test/test_custom_matcher.rb", "test/test_enumerable_expectations.rb", "test/test_error_expectations.rb", "test/test_expectation_builder.rb", "test/test_helper.rb", "test/test_matcher_builder.rb", "test/test_modals.rb", "test/test_operator_expectations.rb", "test/test_truth_expectations.rb"]
|
26
|
+
end
|