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.
@@ -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,10 @@
1
+ module Matchy
2
+ module CustomMatcher
3
+ include Matchy::MatcherBuilder
4
+ def custom_matcher(matcher_name, &block)
5
+ define_method matcher_name do |*args|
6
+ build_matcher(matcher_name, args, &block)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Matchy
2
+ module ExpectationBuilder
3
+ def self.build_expectation(match, exp, obj)
4
+ return Matchy::Expectations::OperatorExpectation.new(obj, match) unless exp
5
+
6
+ (exp.matches?(obj) != match) ? exp.fail!(match) : exp.pass!(match)
7
+ end
8
+ end
9
+ 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)
@@ -0,0 +1,9 @@
1
+ module Matchy
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 4
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -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