MacSpec 0.3.1

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.
Files changed (59) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +20 -0
  5. data/Rakefile +53 -0
  6. data/lib/mac_spec.rb +59 -0
  7. data/lib/mac_spec/matcher_system.rb +19 -0
  8. data/lib/mac_spec/matcher_system/built_in/change_expectations.rb +36 -0
  9. data/lib/mac_spec/matcher_system/built_in/enumerable_expectations.rb +43 -0
  10. data/lib/mac_spec/matcher_system/built_in/error_expectations.rb +68 -0
  11. data/lib/mac_spec/matcher_system/built_in/operator_expectations.rb +45 -0
  12. data/lib/mac_spec/matcher_system/built_in/truth_expectations.rb +148 -0
  13. data/lib/mac_spec/matcher_system/core/def_matcher.rb +14 -0
  14. data/lib/mac_spec/matcher_system/core/exceptions.rb +7 -0
  15. data/lib/mac_spec/matcher_system/core/expectation_builder.rb +11 -0
  16. data/lib/mac_spec/matcher_system/core/matcher_builder.rb +53 -0
  17. data/lib/mac_spec/matcher_system/core/modals.rb +36 -0
  18. data/lib/mac_spec/mocking_framework.rb +13 -0
  19. data/lib/mac_spec/mocking_framework/extensions/kernel_extension.rb +14 -0
  20. data/lib/mac_spec/mocking_framework/extensions/object_extension.rb +74 -0
  21. data/lib/mac_spec/mocking_framework/message_expectation.rb +127 -0
  22. data/lib/mac_spec/mocking_framework/mock.rb +20 -0
  23. data/lib/mac_spec/testing_framework.rb +13 -0
  24. data/lib/mac_spec/testing_framework/core/functions.rb +26 -0
  25. data/lib/mac_spec/testing_framework/core/kernel_extension.rb +27 -0
  26. data/lib/mac_spec/testing_framework/core/test_case_class_methods.rb +90 -0
  27. data/lib/mac_spec/version.rb +3 -0
  28. data/test/all.rb +6 -0
  29. data/test/mac_spec/matcher_system/built_in/change_expectations_test.rb +68 -0
  30. data/test/mac_spec/matcher_system/built_in/enumerable_expectations_test.rb +91 -0
  31. data/test/mac_spec/matcher_system/built_in/error_expectations_test.rb +144 -0
  32. data/test/mac_spec/matcher_system/built_in/operator_expectations_test.rb +136 -0
  33. data/test/mac_spec/matcher_system/built_in/truth_expectations_test.rb +373 -0
  34. data/test/mac_spec/matcher_system/core/def_matcher_test.rb +100 -0
  35. data/test/mac_spec/matcher_system/core/expectation_builder_test.rb +34 -0
  36. data/test/mac_spec/matcher_system/core/matcher_builder_test.rb +72 -0
  37. data/test/mac_spec/matcher_system/core/modals_test.rb +39 -0
  38. data/test/mac_spec/matcher_system/script.rb +29 -0
  39. data/test/mac_spec/matcher_system/test_helper.rb +2 -0
  40. data/test/mac_spec/mocking_framework/extensions/kernel_extension_test.rb +37 -0
  41. data/test/mac_spec/mocking_framework/extensions/object_extension_test.rb +9 -0
  42. data/test/mac_spec/mocking_framework/message_expectation_test.rb +9 -0
  43. data/test/mac_spec/mocking_framework/mock_test.rb +9 -0
  44. data/test/mac_spec/mocking_framework/regression/mocking_class_methods_test.rb +96 -0
  45. data/test/mac_spec/mocking_framework/regression/negative_expectation_test.rb +33 -0
  46. data/test/mac_spec/mocking_framework/regression/stub_test.rb +19 -0
  47. data/test/mac_spec/mocking_framework/test_helper.rb +1 -0
  48. data/test/mac_spec/test_helper.rb +1 -0
  49. data/test/mac_spec/testing_framework/performance/x_test_performance.rb +125 -0
  50. data/test/mac_spec/testing_framework/regression/before_test.rb +32 -0
  51. data/test/mac_spec/testing_framework/regression/deep_nested_example_groups_test.rb +20 -0
  52. data/test/mac_spec/testing_framework/regression/description_string_test.rb +13 -0
  53. data/test/mac_spec/testing_framework/regression/example_name_test.rb +11 -0
  54. data/test/mac_spec/testing_framework/regression/inherit_not_double_test.rb +39 -0
  55. data/test/mac_spec/testing_framework/regression/surrounding_module_scope_test.rb +31 -0
  56. data/test/mac_spec/testing_framework/regression/testing_functions_test.rb +66 -0
  57. data/test/mac_spec/testing_framework/test_helper.rb +1 -0
  58. data/test/test_helper.rb +1 -0
  59. metadata +150 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Matthias Hennemeyer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ = MacSpec
2
+
3
+ MacSpec is a (yet) feature minimal RSpec clone that is specifically built to work with MacRuby.
4
+ It is built ontop of MiniTest that ships with MacRuby and works out of the box with the MacRuby App
5
+ Template for Xcode. All you have to do is to replace two lines of code and start writing your tests.
6
+ No special command for running tests required. Just set your active Target to Test and hit Cmd-B.
7
+
8
+ MacSpec ships with a testing framework similar to RSpec's.
9
+
10
+ The matchy matcher system is built in. (-> http://github.com/jm/matchy)
11
+
12
+ Even a mocking framework is built in.
13
+
14
+ == Philosophy
15
+
16
+ The highest priority feature will always be MacRuby compatibility. We will expand MacSpec's feature set towards RSpec's feature set step by step.
17
+
18
+ == Copyright
19
+
20
+ Copyright (c) 2010 Matthias Hennemeyer. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'lib/mac_spec/version.rb'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.version = MacSpec::VERSION
9
+ gem.name = "MacSpec"
10
+ gem.summary = %Q{MacSpec is a feature minimal RSpec clone that is specifically built to work with MacRuby.}
11
+ gem.description = %Q{MacSpec is a feature minimal RSpec clone that is specifically built to work with MacRuby.}
12
+ gem.email = "mhennemeyer@me.com"
13
+ gem.homepage = "http://github.com/mhennemeyer/MacSpec"
14
+ gem.authors = ["Matthias Hennemeyer"]
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "MacSpec #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/lib/mac_spec.rb ADDED
@@ -0,0 +1,59 @@
1
+ require "rubygems"
2
+ require "minitest/unit"
3
+ $:.unshift(File.dirname(__FILE__)) unless
4
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ module MacSpec
7
+ class << self
8
+
9
+ def assert(bool=false)
10
+ @current_test_case.assert(bool)
11
+ end
12
+
13
+ def flunk(msg="No Error Message given.")
14
+ @current_test_case.flunk(msg)
15
+ end
16
+
17
+ def current_test_case
18
+ @current_test_case
19
+ end
20
+
21
+ def current_test_case=(tc)
22
+ @current_test_case = tc
23
+ end
24
+
25
+ def assertions_module
26
+ MiniTest::Assertions
27
+ end
28
+
29
+ def test_case_class
30
+ MiniTest::Unit::TestCase
31
+ end
32
+
33
+ def assertion_failed_error
34
+ MiniTest::Assertion
35
+ end
36
+ end
37
+ end
38
+ MiniTest::Unit.autorun unless defined?(MacSpecNoAutoRun)
39
+ require 'mac_spec/version'
40
+ require 'mac_spec/matcher_system'
41
+ require 'mac_spec/testing_framework'
42
+ require 'mac_spec/mocking_framework'
43
+ unless defined?(LOADED)
44
+ # Track the current testcase and
45
+ # provide it to the operator matchers and mocking framework.
46
+ # Otherwise expectations won't be counted as assertions
47
+ # todo no global
48
+ MacSpec.test_case_class.class_eval do
49
+ alias_method :old_run_method_aliased_by_macspec, :run
50
+ def run(whatever, *args, &block)
51
+ MacSpec.current_test_case = self
52
+ old_run_method_aliased_by_macspec(whatever, *args, &block)
53
+ end
54
+ end
55
+ LOADED = true
56
+ end
57
+
58
+ MacSpec.test_case_class.send(:include, MacSpec::MatcherSystem::Expectations::TestCaseExtensions)
59
+ include MacSpec::MatcherSystem::DefMatcher
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ require 'matcher_system/core/expectation_builder'
4
+ require 'matcher_system/core/modals'
5
+ require 'matcher_system/core/matcher_builder'
6
+ require 'matcher_system/core/def_matcher'
7
+ require 'matcher_system/core/exceptions'
8
+
9
+ require 'matcher_system/built_in/enumerable_expectations'
10
+ require 'matcher_system/built_in/error_expectations'
11
+ require 'matcher_system/built_in/truth_expectations'
12
+ require 'matcher_system/built_in/operator_expectations'
13
+ require 'matcher_system/built_in/change_expectations'
14
+
15
+ module MacSpec
16
+ module MatcherSystem
17
+ # todo doc
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ module MacSpec
2
+ module MatcherSystem
3
+ module Expectations
4
+ module TestCaseExtensions
5
+ # Checks if the given block alters the value of the block attached to change
6
+ #
7
+ # ==== Examples
8
+ # lambda {var += 1}.should change {var}.by(1)
9
+ # lambda {var += 2}.should change {var}.by_at_least(1)
10
+ # lambda {var += 1}.should change {var}.by_at_most(1)
11
+ # lambda {var += 2}.should change {var}.from(1).to(3) if var = 1
12
+ def change(&block)
13
+ build_matcher(:change) do |receiver, matcher, args|
14
+ before, done, after = block.call, receiver.call, block.call
15
+ comparison = (after != before)
16
+ specifiers = matcher.chained_messages
17
+ if specifiers
18
+ comparison = case specifiers[0].name
19
+ # todo: provide meaningful messages
20
+ when :by then (after == before + specifiers[0].args[0] || after == before - specifiers[0].args[0])
21
+ when :by_at_least then (after >= before + specifiers[0].args[0] || after <= before - specifiers[0].args[0])
22
+ when :by_at_most then (after <= before + specifiers[0].args[0] && after >= before - specifiers[0].args[0])
23
+ when :from then (before == specifiers[0].args[0]) && (after == specifiers[1].args[0])
24
+ else raise MacSpec::MatcherSystem::Exceptions::UnsupportedMessageSentToMatcher.new(
25
+ "Message: #{specifiers[0].name} sent to change matcher.")
26
+ end
27
+ end
28
+ matcher.positive_msg = "given block shouldn't alter the block attached to change"
29
+ matcher.negative_msg = "given block should alter the block attached to change"
30
+ comparison
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,43 @@
1
+ module MacSpec
2
+ module MatcherSystem
3
+ module Expectations
4
+ module TestCaseExtensions
5
+
6
+ # Calls +include?+ on the receiver for any object. You can also provide
7
+ # multiple arguments to see if all of them are included.
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # [1,2,3].should include(1)
12
+ # [7,8,8].should_not include(3)
13
+ # ['a', 'b', 'c'].should include('a', 'c')
14
+ #
15
+ def include(*obj)
16
+ _clude(:include, obj)
17
+ end
18
+
19
+ # Expects the receiver to exclude the given object(s). You can provide
20
+ # multiple arguments to see if all of them are included.
21
+ #
22
+ # ==== Examples
23
+ #
24
+ # [1,2,3].should exclude(16)
25
+ # [7,8,8].should_not exclude(7)
26
+ # ['a', 'b', 'c'].should exclude('e', 'f', 'g')
27
+ #
28
+ def exclude(*obj)
29
+ _clude(:exclude, obj)
30
+ end
31
+
32
+ private
33
+ def _clude(sym, obj)
34
+ build_matcher(sym, obj) do |given, matcher, args|
35
+ matcher.positive_msg = "Expected #{given.inspect} to #{sym} #{args.inspect}."
36
+ matcher.negative_msg = "Expected #{given.inspect} to not #{sym} #{args.inspect}."
37
+ args.inject(true) {|m,o| m && (given.include?(o) == (sym == :include)) }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,68 @@
1
+ module MacSpec
2
+ module MatcherSystem
3
+ module Expectations
4
+ module TestCaseExtensions
5
+ # Expects a lambda to raise an error. You can specify the error or leave it blank to encompass
6
+ # any error.
7
+ #
8
+ # ==== Examples
9
+ #
10
+ # lambda { raise "FAILURE." }.should raise_error
11
+ # lambda { puts i_dont_exist }.should raise_error(NameError)
12
+ #
13
+ def raise_error(*obj)
14
+ build_matcher(:raise_error, obj) do |receiver, matcher, args|
15
+ expected = args[0] || Exception
16
+ raised = false
17
+ error = nil
18
+ begin
19
+ receiver.call
20
+ rescue Exception => e
21
+ raised = true
22
+ error = e
23
+ end
24
+ if expected.respond_to?(:ancestors) && expected.ancestors.include?(Exception)
25
+ matcher.positive_msg = "Expected #{receiver.inspect} to raise #{expected.name}, " +
26
+ (error ? "but #{error.class.name} was raised instead." : "but none was raised.")
27
+ matcher.negative_msg = "Expected #{receiver.inspect} to not raise #{expected.name}."
28
+ comparison = (raised && error.class.ancestors.include?(expected))
29
+ else
30
+ message = error ? error.message : "none"
31
+ matcher.positive_msg = "Expected #{receiver.inspect} to raise error with message matching '#{expected}', but '#{message}' was raised."
32
+ matcher.negative_msg = "Expected #{receiver.inspect} to raise error with message not matching '#{expected}', but '#{message}' was raised."
33
+ comparison = (raised && (expected.kind_of?(Regexp) ? ((error.message =~ expected) ? true : false) : expected == error.message))
34
+ end
35
+ comparison
36
+ end
37
+ end
38
+
39
+ # Expects a lambda to throw an error.
40
+ #
41
+ # ==== Examples
42
+ #
43
+ # lambda { throw :thing }.should throw_symbol(:thing)
44
+ # lambda { "not this time" }.should_not throw_symbol(:hello)
45
+ #
46
+ def throw_symbol(*obj)
47
+ build_matcher(:throw_symbol, obj) do |receiver, matcher, args|
48
+ raised, thrown_symbol, expected = false, nil, args[0]
49
+ begin
50
+ receiver.call
51
+ rescue NameError => e
52
+ raise e unless e.message =~ /uncaught throw/
53
+ raised = true
54
+ thrown_symbol = e.name.to_sym if e.respond_to?(:name)
55
+ rescue ArgumentError => e
56
+ raise e unless e.message =~ /uncaught throw/
57
+ thrown_symbol = e.message.match(/uncaught throw :(.+)/)[1].to_sym
58
+ end
59
+ matcher.positive_msg = "Expected #{receiver.inspect} to throw :#{expected}, but " +
60
+ "#{thrown_symbol ? ':' + thrown_symbol.to_s + ' was thrown instead' : 'no symbol was thrown'}."
61
+ matcher.negative_msg = "Expected #{receiver.inspect} to not throw :#{expected}."
62
+ expected == thrown_symbol
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,45 @@
1
+ module MacSpec
2
+ module MatcherSystem
3
+ module Expectations
4
+ # Class to handle operator expectations.
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # 13.should == 13
9
+ # "hello".length.should_not == 2
10
+ #
11
+ class OperatorExpectation #< Base
12
+ include ::MacSpec.assertions_module
13
+
14
+ def initialize(receiver, match)
15
+ @receiver, @match = receiver, match
16
+ end
17
+
18
+ ['==', '===', '=~', '>', '>=', '<', '<='].each do |op|
19
+ define_method(op) do |expected|
20
+ @expected = expected
21
+ (@receiver.send(op,expected) ? true : false) == @match ? pass! : fail!(op)
22
+ end
23
+ end
24
+
25
+ protected
26
+ def pass!
27
+ MacSpec.assert(true)
28
+ end
29
+
30
+ def fail!(operator)
31
+ msg = @match ? failure_message(operator) : negative_failure_message(operator)
32
+ MacSpec.flunk msg
33
+ end
34
+
35
+ def failure_message(operator)
36
+ "Expected #{@receiver.inspect} to #{operator} #{@expected.inspect}."
37
+ end
38
+
39
+ def negative_failure_message(operator)
40
+ "Expected #{@receiver.inspect} to not #{operator} #{@expected.inspect}."
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,148 @@
1
+ module MacSpec
2
+ module MatcherSystem
3
+ module Expectations
4
+ module TestCaseExtensions
5
+ # Simply checks if the receiver matches the expected object.
6
+ # TODO: Fill this out to implement much of the RSpec functionality (and then some)
7
+ #
8
+ # ==== Examples
9
+ #
10
+ # "hello".should be("hello")
11
+ # (13 < 20).should be(true)
12
+ #
13
+ def be(*obj)
14
+ build_matcher(:be, obj) do |receiver, matcher, args|
15
+ @receiver, expected = receiver, args[0]
16
+ matcher.positive_msg = "Expected #{@receiver.inspect} to be #{expected.inspect}."
17
+ matcher.negative_msg = "Expected #{@receiver.inspect} to not be #{expected.inspect}."
18
+ expected == @receiver
19
+ end
20
+ end
21
+
22
+ # Checks if the given object is within a given object and delta.
23
+ #
24
+ # ==== Examples
25
+ #
26
+ # (20.0 - 2.0).should be_close(18.0)
27
+ # (13.0 - 4.0).should be_close(9.0, 0.5)
28
+ #
29
+ def be_close(obj, delta = 0.3)
30
+ build_matcher(:be_close, [obj, delta]) do |receiver, matcher, args|
31
+ @receiver, expected, delta = receiver, args[0], args[1]
32
+ matcher.positive_msg = "Expected #{@receiver.inspect} to be close to #{expected.inspect} (delta: #{delta})."
33
+ matcher.negative_msg = "Expected #{@receiver.inspect} to not be close to #{expected.inspect} (delta: #{delta})."
34
+ (@receiver - expected).abs < delta
35
+ end
36
+ end
37
+
38
+ # Calls +exist?+ on the given object.
39
+ #
40
+ # ==== Examples
41
+ #
42
+ # # found_user.exist?
43
+ # found_user.should exist
44
+ #
45
+ def exist
46
+ ask_for(:exist, :with_arg => nil)
47
+ end
48
+
49
+ # Calls +eql?+ on the given object (i.e., are the objects the same value?)
50
+ #
51
+ # ==== Examples
52
+ #
53
+ # 1.should_not eql(1.0)
54
+ # (12 / 6).should eql(6)
55
+ #
56
+ def eql(*obj)
57
+ ask_for(:eql, :with_arg => obj)
58
+ end
59
+
60
+ # Calls +equal?+ on the given object (i.e., do the two objects have the same +object_id+?)
61
+ #
62
+ # ==== Examples
63
+ #
64
+ # x = [1,2,3]
65
+ # y = [1,2,3]
66
+ #
67
+ # # Different object_id's...
68
+ # x.should_not equal(y)
69
+ #
70
+ # # The same object_id
71
+ # x[0].should equal(y[0])
72
+ #
73
+ def equal(*obj)
74
+ ask_for(:equal, :with_arg => obj)
75
+ end
76
+
77
+ # A last ditch way to implement your testing logic. You probably shouldn't use this unless you
78
+ # have to.
79
+ #
80
+ # ==== Examples
81
+ #
82
+ # (13 - 4).should satisfy(lambda {|i| i < 20})
83
+ # "hello".should_not satisfy(lambda {|s| s =~ /hi/})
84
+ #
85
+ def satisfy(*obj)
86
+ build_matcher(:satisfy, obj) do |receiver, matcher, args|
87
+ @receiver, expected = receiver, args[0]
88
+ matcher.positive_msg = "Expected #{@receiver.inspect} to satisfy given block."
89
+ matcher.negative_msg = "Expected #{@receiver.inspect} to not satisfy given block."
90
+ expected.call(@receiver) == true
91
+ end
92
+ end
93
+
94
+ # Checks if the given object responds to the given method
95
+ #
96
+ # ==== Examples
97
+ #
98
+ # "foo".should respond_to(:length)
99
+ # {}.should respond_to(:has_key?)
100
+ def respond_to(*meth)
101
+ ask_for(:respond_to, :with_arg => meth)
102
+ end
103
+
104
+ # Asks given for success?().
105
+ # This is necessary because Rails Integration::Session
106
+ # overides method_missing without grace.
107
+ #
108
+ # ==== Examples
109
+ #
110
+ # @response.should be_success
111
+ def be_success
112
+ ask_for(:success, :with_arg => nil)
113
+ end
114
+
115
+ alias_method :old_missing, :method_missing
116
+ # ==be_*something(*args)
117
+ #
118
+ # ===This method_missing acts as a matcher builder.
119
+ # If a call to be_xyz() reaches this method_missing (say: obj.should be_xyz),
120
+ # a matcher with the name xyz will be built, whose defining property
121
+ # is that it returns the value of obj.xyz? for matches?.
122
+ # ==== Examples
123
+ #
124
+ # nil.should be_nil
125
+ # 17.should be_kind_of(Fixnum)
126
+ # obj.something? #=> true
127
+ # obj.should be_something
128
+ def method_missing(name, *args, &block)
129
+ if (name.to_s =~ /^be_(.+)/)
130
+ ask_for($1, :with_arg => args)
131
+ else
132
+ old_missing(name, *args, &block)
133
+ end
134
+ end
135
+
136
+ private
137
+ def ask_for(sym, option={})
138
+ build_matcher(sym, (option[:with_arg] || [])) do |receiver, matcher, args|
139
+ expected, meth = args[0], (sym.to_s + "?" ).to_sym
140
+ matcher.positive_msg = "Expected #{receiver.inspect} to return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
141
+ matcher.negative_msg = "Expected #{receiver.inspect} to not return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
142
+ expected ? receiver.send(meth, expected) : receiver.send(meth)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end