MacSpec 0.3.1

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