jnunemaker-matchy 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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