mocha 0.5.6 → 0.9.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.
Files changed (120) hide show
  1. data/README +4 -4
  2. data/RELEASE +45 -0
  3. data/Rakefile +55 -33
  4. data/lib/mocha.rb +1 -0
  5. data/lib/mocha/any_instance_method.rb +24 -4
  6. data/lib/mocha/backtrace_filter.rb +17 -0
  7. data/lib/mocha/cardinality.rb +92 -0
  8. data/lib/mocha/central.rb +1 -9
  9. data/lib/mocha/change_state_side_effect.rb +19 -0
  10. data/lib/mocha/class_method.rb +25 -5
  11. data/lib/mocha/configuration.rb +60 -0
  12. data/lib/mocha/exception_raiser.rb +1 -1
  13. data/lib/mocha/expectation.rb +109 -48
  14. data/lib/mocha/expectation_error.rb +6 -6
  15. data/lib/mocha/expectation_list.rb +10 -14
  16. data/lib/mocha/in_state_ordering_constraint.rb +19 -0
  17. data/lib/mocha/instance_method.rb +9 -0
  18. data/lib/mocha/logger.rb +15 -0
  19. data/lib/mocha/mock.rb +19 -14
  20. data/lib/mocha/mockery.rb +166 -0
  21. data/lib/mocha/module_method.rb +17 -0
  22. data/lib/mocha/names.rb +53 -0
  23. data/lib/mocha/object.rb +26 -9
  24. data/lib/mocha/parameter_matchers.rb +2 -1
  25. data/lib/mocha/parameter_matchers/all_of.rb +3 -3
  26. data/lib/mocha/parameter_matchers/any_of.rb +3 -3
  27. data/lib/mocha/parameter_matchers/anything.rb +1 -1
  28. data/lib/mocha/parameter_matchers/has_entries.rb +4 -1
  29. data/lib/mocha/parameter_matchers/has_entry.rb +3 -2
  30. data/lib/mocha/parameter_matchers/has_key.rb +1 -1
  31. data/lib/mocha/parameter_matchers/has_value.rb +1 -1
  32. data/lib/mocha/parameter_matchers/not.rb +2 -2
  33. data/lib/mocha/parameter_matchers/object.rb +1 -1
  34. data/lib/mocha/parameter_matchers/optionally.rb +22 -0
  35. data/lib/mocha/parameter_matchers/regexp_matches.rb +2 -2
  36. data/lib/mocha/parameter_matchers/responds_with.rb +43 -0
  37. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +43 -0
  38. data/lib/mocha/single_return_value.rb +2 -9
  39. data/lib/mocha/standalone.rb +151 -17
  40. data/lib/mocha/state_machine.rb +91 -0
  41. data/lib/mocha/stubbing_error.rb +16 -0
  42. data/lib/mocha/test_case_adapter.rb +76 -22
  43. data/lib/stubba.rb +2 -1
  44. data/test/acceptance/acceptance_test_helper.rb +38 -0
  45. data/test/acceptance/bug_18914_test.rb +43 -0
  46. data/test/acceptance/{expected_invocation_count_acceptance_test.rb → expected_invocation_count_test.rb} +29 -20
  47. data/test/acceptance/failure_messages_test.rb +64 -0
  48. data/test/acceptance/{mocha_acceptance_test.rb → mocha_example_test.rb} +5 -5
  49. data/test/{integration/mocha_test_result_integration_test.rb → acceptance/mocha_test_result_test.rb} +19 -40
  50. data/test/acceptance/mock_test.rb +100 -0
  51. data/test/acceptance/{mock_with_initializer_block_acceptance_test.rb → mock_with_initializer_block_test.rb} +12 -5
  52. data/test/acceptance/{mocked_methods_dispatch_acceptance_test.rb → mocked_methods_dispatch_test.rb} +12 -5
  53. data/test/acceptance/{optional_parameters_acceptance_test.rb → optional_parameters_test.rb} +11 -4
  54. data/test/acceptance/{parameter_matcher_acceptance_test.rb → parameter_matcher_test.rb} +67 -5
  55. data/test/acceptance/{partial_mocks_acceptance_test.rb → partial_mocks_test.rb} +12 -5
  56. data/test/acceptance/return_value_test.rb +52 -0
  57. data/test/acceptance/{sequence_acceptance_test.rb → sequence_test.rb} +13 -6
  58. data/test/acceptance/{standalone_acceptance_test.rb → standalone_test.rb} +19 -11
  59. data/test/acceptance/states_test.rb +70 -0
  60. data/test/acceptance/stub_any_instance_method_test.rb +195 -0
  61. data/test/acceptance/stub_class_method_test.rb +203 -0
  62. data/test/acceptance/stub_everything_test.rb +56 -0
  63. data/test/acceptance/stub_instance_method_test.rb +165 -0
  64. data/test/acceptance/stub_module_method_test.rb +163 -0
  65. data/test/acceptance/stub_test.rb +52 -0
  66. data/test/acceptance/{stubba_acceptance_test.rb → stubba_example_test.rb} +1 -1
  67. data/test/{integration/stubba_test_result_integration_test.rb → acceptance/stubba_test_result_test.rb} +17 -36
  68. data/test/acceptance/stubbing_error_backtrace_test.rb +64 -0
  69. data/test/acceptance/stubbing_method_unnecessarily_test.rb +65 -0
  70. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +130 -0
  71. data/test/acceptance/stubbing_non_existent_class_method_test.rb +155 -0
  72. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +145 -0
  73. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +130 -0
  74. data/test/acceptance/stubbing_non_public_class_method_test.rb +161 -0
  75. data/test/acceptance/stubbing_non_public_instance_method_test.rb +141 -0
  76. data/test/acceptance/stubbing_on_non_mock_object_test.rb +64 -0
  77. data/test/execution_point.rb +3 -1
  78. data/test/simple_counter.rb +13 -0
  79. data/test/test_helper.rb +0 -1
  80. data/test/test_runner.rb +6 -4
  81. data/test/unit/any_instance_method_test.rb +1 -1
  82. data/test/unit/array_inspect_test.rb +1 -1
  83. data/test/unit/backtrace_filter_test.rb +19 -0
  84. data/test/unit/cardinality_test.rb +56 -0
  85. data/test/unit/central_test.rb +4 -63
  86. data/test/unit/change_state_side_effect_test.rb +41 -0
  87. data/test/unit/class_method_test.rb +38 -1
  88. data/test/unit/date_time_inspect_test.rb +1 -1
  89. data/test/unit/{expectation_raiser_test.rb → exception_raiser_test.rb} +14 -0
  90. data/test/unit/expectation_list_test.rb +4 -22
  91. data/test/unit/expectation_test.rb +70 -94
  92. data/test/unit/in_state_ordering_constraint_test.rb +43 -0
  93. data/test/unit/mock_test.rb +16 -37
  94. data/test/unit/mockery_test.rb +149 -0
  95. data/test/unit/{no_yield_test.rb → no_yields_test.rb} +0 -0
  96. data/test/unit/object_test.rb +6 -89
  97. data/test/unit/parameter_matchers/equals_test.rb +25 -0
  98. data/test/unit/parameter_matchers/has_entries_test.rb +22 -1
  99. data/test/unit/parameter_matchers/has_entry_test.rb +24 -2
  100. data/test/unit/parameter_matchers/has_key_test.rb +11 -0
  101. data/test/unit/parameter_matchers/has_value_test.rb +12 -0
  102. data/test/unit/parameter_matchers/regexp_matches_test.rb +1 -1
  103. data/test/unit/parameter_matchers/responds_with_test.rb +25 -0
  104. data/test/unit/parameter_matchers/stub_matcher.rb +4 -0
  105. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +25 -0
  106. data/test/unit/single_return_value_test.rb +0 -19
  107. data/test/unit/state_machine_test.rb +98 -0
  108. metadata +108 -69
  109. data/lib/mocha/auto_verify.rb +0 -118
  110. data/lib/mocha/infinite_range.rb +0 -25
  111. data/lib/mocha/missing_expectation.rb +0 -17
  112. data/lib/mocha/setup_and_teardown.rb +0 -23
  113. data/lib/mocha/stub.rb +0 -18
  114. data/test/integration/stubba_integration_test.rb +0 -89
  115. data/test/unit/auto_verify_test.rb +0 -129
  116. data/test/unit/expectation_error_test.rb +0 -24
  117. data/test/unit/infinite_range_test.rb +0 -53
  118. data/test/unit/missing_expectation_test.rb +0 -42
  119. data/test/unit/setup_and_teardown_test.rb +0 -76
  120. data/test/unit/stub_test.rb +0 -24
data/README CHANGED
@@ -1,12 +1,12 @@
1
1
  = Mocha
2
2
 
3
- Mocha is a library for mocking and stubbing using a syntax like that of JMock[http://www.jmock.org], and SchMock[http://rubyforge.org/projects/schmock]. Most commonly Mocha is used in conjunction with Test::Unit[http://www.ruby-doc.org/core/classes/Test/Unit.html], but it can be used in other contexts.
3
+ Mocha is a library for mocking and stubbing using a syntax like that of JMock[http://www.jmock.org].
4
4
 
5
- One of its main advantages is that it allows you to mock and stub methods on _real_ (non-mock) classes and instances. You can for example stub ActiveRecord[http://api.rubyonrails.com/classes/ActiveRecord/Base.html] instance methods like +create+, +save+, +destroy+ and even class methods like +find+ to avoid hitting the database in unit tests.
5
+ It can be used with many testing frameworks e.g. Test::Unit[http://www.ruby-doc.org/core/classes/Test/Unit.html], RSpec[http://rspec.info/], test/spec[http://chneukirchen.org/repos/testspec/README], expectations[http://expectations.rubyforge.org/], Dust[http://dust.rubyforge.org/] and even JtestR[http://jtestr.codehaus.org/].
6
6
 
7
- Mocha provides a unified, simple and readable syntax for both traditional mocking and for mocking with _real_ objects.
7
+ Mocha provides a unified, simple and readable syntax for both traditional mocking and partial mocking.
8
8
 
9
- Mocha has been harvested from projects at Reevoo[http://www.reevoo.com] by me (James[http://blog.floehopper.org]) and my colleagues Ben[http://www.reevoo.com/blogs/bengriffiths], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com]. Mocha is in use on real-world Rails[http://www.rubyonrails.org] projects.
9
+ Mocha was harvested from projects at Reevoo[http://www.reevoo.com] by me (James[http://blog.floehopper.org]) and my colleagues Ben[http://www.techbelly.com/], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com].
10
10
 
11
11
  == Download and Installation
12
12
 
data/RELEASE CHANGED
@@ -1,3 +1,48 @@
1
+ = 0.9.0
2
+
3
+ * Configurable warnings or errors
4
+ * when a method on a non-public method is stubbed
5
+ * when a method on a non-existent method is stubbed
6
+ * when a method on a non-mock object is stubbed
7
+ * when a method is stubbed unnecessarily (i.e. the stubbed method is not called during the test)
8
+
9
+ * Improved error messages
10
+ * User-friendly list of unsatisfied expectations, satisfied expectations and state machines.
11
+ * Improved readability of cardinality description.
12
+ * Display sensible failure message for any_instance expectations e.g. "#<AnyInstance:Foo>.bar - expected calls: 1, actual calls: 0"
13
+
14
+ * Parameter matchers
15
+ * New to this release
16
+ * optionally (allows matching of optional parameters if available)
17
+ * yaml_equivalent (allows matching of YAML that represents the specified object)
18
+ * responds_with (tests the quack not the duck)
19
+ * Nesting of parameter matchers is now supported.
20
+
21
+ * Optional block passed into mock initializer is evaluated in the context of the new mock instance and can be used as a shortcut to set up expectations.
22
+
23
+ * Added JMock-style sequences for constraining the order of expected invocations. See Standalone#sequence and Expectation#in_sequence.
24
+
25
+ * Added JMock-style states for constraining the order of expected invocations. See Standalone#states, Expectation#then, Expectation#when and StateMachine.
26
+
27
+ * Compatibility with versions of Ruby
28
+ * Compatibility with Ruby v1.9. All test errors and warnings fixed.
29
+ * Nasty fix so that TestCaseAdaptor works consistently with earlier versions of Test::Unit as well as more recent versions.
30
+ * Added platform to gem specification to avoid bug in rubygems 0.9.5 - see http://www.dcmanges.com/blog/rubygems-0-9-5-platform-bug and http://rubygems.org/read/chapter/20#platform.
31
+ * Make ExpectationRaiser deal with subclasses of Interrupt which seem to need a message supplied in the raise statement in Ruby 1.8.6 (but not 1.8.4 or 1.9). Not sure this is really Mocha's responsibility.
32
+
33
+ * Added deprecation warning in stubba.rb which is no longer needed and will be removed.
34
+
35
+ * Supply positioning information to evals to improve any error messages. See http://ola-bini.blogspot.com/2008/01/ruby-antipattern-using-eval-without.html
36
+
37
+ * Bug fixes
38
+ * 18914 in revision 296 - http://rubyforge.org/tracker/index.php?func=detail&aid=18914&group_id=1917&atid=7477
39
+ * 18917 in revision 295 - http://rubyforge.org/tracker/index.php?func=detail&aid=18917&group_id=1917&atid=7477
40
+ * 18336 in revision 287 - http://rubyforge.org/tracker/index.php?func=detail&aid=18336&group_id=1917&atid=7477
41
+ * 17835 in revision 255 - http://rubyforge.org/tracker/index.php?func=detail&aid=17835&group_id=1917&atid=7477
42
+ * 17412 in revision 242 - http://rubyforge.org/tracker/index.php?func=detail&aid=17412&group_id=1917&atid=7477
43
+ * 15977 in revision 198 - http://rubyforge.org/tracker/index.php?func=detail&aid=15977&group_id=1917&atid=7477
44
+ * 11885 in revision 156 - http://rubyforge.org/tracker/index.php?func=detail&aid=11885&group_id=1917&atid=7477
45
+
1
46
  = 0.5.5 (r167)
2
47
 
3
48
  - Renamed Matches parameter matcher to RegexpMatches for clarity.
data/Rakefile CHANGED
@@ -5,50 +5,72 @@ require 'rake/testtask'
5
5
  require 'rake/contrib/sshpublisher'
6
6
 
7
7
  module Mocha
8
- VERSION = "0.5.6"
8
+ VERSION = "0.9.0"
9
9
  end
10
10
 
11
11
  desc "Run all tests"
12
- task :default => :test_all
13
-
14
- task :test_all => [:test_unit, :test_integration, :test_acceptance]
15
-
16
- desc "Run unit tests"
17
- Rake::TestTask.new(:test_unit) do |t|
18
- t.libs << 'test'
19
- t.test_files = FileList['test/unit/**/*_test.rb']
20
- t.verbose = true
21
- t.warning = true
22
- end
12
+ task 'default' => ['test:units', 'test:acceptance']
13
+
14
+ namespace 'test' do
15
+
16
+ unit_tests = FileList['test/unit/**/*_test.rb']
17
+ acceptance_tests = FileList['test/acceptance/*_test.rb']
18
+
19
+ desc "Run unit tests"
20
+ Rake::TestTask.new('units') do |t|
21
+ t.libs << 'test'
22
+ t.test_files = unit_tests
23
+ t.verbose = true
24
+ t.warning = true
25
+ end
23
26
 
24
- desc "Run integration tests"
25
- Rake::TestTask.new(:test_integration) do |t|
26
- t.libs << 'test'
27
- t.test_files = FileList['test/integration/*_test.rb']
28
- t.verbose = true
29
- t.warning = true
30
- end
27
+ desc "Run acceptance tests"
28
+ Rake::TestTask.new('acceptance') do |t|
29
+ t.libs << 'test'
30
+ t.test_files = acceptance_tests
31
+ t.verbose = true
32
+ t.warning = true
33
+ end
34
+
35
+ # require 'rcov/rcovtask'
36
+ # Rcov::RcovTask.new('coverage') do |t|
37
+ # t.libs << 'test'
38
+ # t.test_files = unit_tests + acceptance_tests
39
+ # t.verbose = true
40
+ # t.warning = true
41
+ # t.rcov_opts << '--sort coverage'
42
+ # t.rcov_opts << '--xref'
43
+ # end
31
44
 
32
- desc "Run acceptance tests"
33
- Rake::TestTask.new(:test_acceptance) do |t|
34
- t.libs << 'test'
35
- t.test_files = FileList['test/acceptance/*_test.rb']
36
- t.verbose = true
37
- t.warning = true
38
45
  end
39
46
 
40
47
  desc 'Generate RDoc'
41
- Rake::RDocTask.new do |task|
48
+ Rake::RDocTask.new('rdoc') do |task|
42
49
  task.main = 'README'
43
50
  task.title = "Mocha #{Mocha::VERSION}"
44
51
  task.rdoc_dir = 'doc'
45
52
  task.template = File.expand_path(File.join(File.dirname(__FILE__), "templates", "html_with_google_analytics"))
46
- task.rdoc_files.include('README', 'RELEASE', 'COPYING', 'MIT-LICENSE', 'agiledox.txt', 'lib/mocha/auto_verify.rb', 'lib/mocha/mock.rb', 'lib/mocha/expectation.rb', 'lib/mocha/object.rb', 'lib/mocha/parameter_matchers.rb', 'lib/mocha/parameter_matchers')
53
+ task.rdoc_files.include(
54
+ 'README',
55
+ 'RELEASE',
56
+ 'COPYING',
57
+ 'MIT-LICENSE',
58
+ 'agiledox.txt',
59
+ 'lib/mocha/standalone.rb',
60
+ 'lib/mocha/mock.rb',
61
+ 'lib/mocha/expectation.rb',
62
+ 'lib/mocha/object.rb',
63
+ 'lib/mocha/parameter_matchers.rb',
64
+ 'lib/mocha/parameter_matchers',
65
+ 'lib/mocha/state_machine.rb',
66
+ 'lib/mocha/configuration.rb',
67
+ 'lib/mocha/stubbing_error.rb'
68
+ )
47
69
  end
48
- task :rdoc => :examples
70
+ task 'rdoc' => 'examples'
49
71
 
50
72
  desc "Upload RDoc to RubyForge"
51
- task :publish_rdoc => [:rdoc, :examples] do
73
+ task 'publish_rdoc' => ['rdoc', 'examples'] do
52
74
  Rake::SshDirPublisher.new("jamesmead@rubyforge.org", "/var/www/gforge-projects/mocha", "doc").upload
53
75
  end
54
76
 
@@ -69,7 +91,7 @@ file 'agiledox.txt' do
69
91
  end
70
92
 
71
93
  desc "Convert example ruby files to syntax-highlighted html"
72
- task :examples do
94
+ task 'examples' do
73
95
  $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "vendor", "coderay-0.7.4.215", "lib"))
74
96
  require 'coderay'
75
97
  mkdir_p 'doc/examples'
@@ -119,16 +141,16 @@ Rake::GemPackageTask.new(specification) do |package|
119
141
  package.need_tar = true
120
142
  end
121
143
 
122
- task :verify_user do
144
+ task 'verify_user' do
123
145
  raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
124
146
  end
125
147
 
126
- task :verify_password do
148
+ task 'verify_password' do
127
149
  raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
128
150
  end
129
151
 
130
152
  desc "Publish package files on RubyForge."
131
- task :publish_packages => [:verify_user, :verify_password, :package] do
153
+ task 'publish_packages' => ['verify_user', 'verify_password', 'package'] do
132
154
  $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "vendor", "meta_project-0.4.15", "lib"))
133
155
  require 'meta_project'
134
156
  require 'rake/contrib/xforge'
@@ -1,5 +1,6 @@
1
1
  require 'mocha_standalone'
2
2
  require 'mocha/test_case_adapter'
3
+ require 'mocha/configuration'
3
4
 
4
5
  require 'test/unit/testcase'
5
6
 
@@ -15,21 +15,41 @@ module Mocha
15
15
  end
16
16
 
17
17
  def hide_original_method
18
- stubbee.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.method_defined?(method)
18
+ if method_exists?(method)
19
+ begin
20
+ stubbee.class_eval("alias_method :#{hidden_method}, :#{method}", __FILE__, __LINE__)
21
+ rescue NameError
22
+ # deal with nasties like ActiveRecord::Associations::AssociationProxy
23
+ end
24
+ end
19
25
  end
20
26
 
21
27
  def define_new_method
22
- stubbee.class_eval "def #{method}(*args, &block); self.class.any_instance.mocha.method_missing(:#{method}, *args, &block); end"
28
+ stubbee.class_eval("def #{method}(*args, &block); self.class.any_instance.mocha.method_missing(:#{method}, *args, &block); end", __FILE__, __LINE__)
23
29
  end
24
30
 
25
31
  def remove_new_method
26
- stubbee.class_eval "remove_method :#{method}"
32
+ stubbee.class_eval("remove_method :#{method}", __FILE__, __LINE__)
27
33
  end
28
34
 
29
35
  def restore_original_method
30
- stubbee.class_eval "alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}" if stubbee.method_defined?(hidden_method)
36
+ if method_exists?(hidden_method)
37
+ begin
38
+ stubbee.class_eval("alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}", __FILE__, __LINE__)
39
+ rescue NameError
40
+ # deal with nasties like ActiveRecord::Associations::AssociationProxy
41
+ end
42
+ end
31
43
  end
32
44
 
45
+ def method_exists?(method)
46
+ existing_methods = []
47
+ existing_methods += stubbee.public_instance_methods(false)
48
+ existing_methods += stubbee.protected_instance_methods(false)
49
+ existing_methods += stubbee.private_instance_methods(false)
50
+ existing_methods.any? { |m| m.to_s == method.to_s }
51
+ end
52
+
33
53
  end
34
54
 
35
55
  end
@@ -0,0 +1,17 @@
1
+ module Mocha
2
+
3
+ class BacktraceFilter
4
+
5
+ LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR
6
+
7
+ def initialize(lib_directory = LIB_DIRECTORY)
8
+ @lib_directory = lib_directory
9
+ end
10
+
11
+ def filtered(backtrace)
12
+ backtrace.reject { |location| Regexp.new(@lib_directory).match(File.expand_path(location)) }
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,92 @@
1
+ module Mocha
2
+
3
+ class Cardinality
4
+
5
+ INFINITY = 1 / 0.0
6
+
7
+ class << self
8
+
9
+ def exactly(count)
10
+ new(count, count)
11
+ end
12
+
13
+ def at_least(count)
14
+ new(count, INFINITY)
15
+ end
16
+
17
+ def at_most(count)
18
+ new(0, count)
19
+ end
20
+
21
+ def times(range_or_count)
22
+ case range_or_count
23
+ when Range
24
+ new(range_or_count.first, range_or_count.last)
25
+ else
26
+ new(range_or_count, range_or_count)
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ def initialize(required, maximum)
33
+ @required, @maximum = required, maximum
34
+ end
35
+
36
+ def invocations_allowed?(invocation_count)
37
+ invocation_count < maximum
38
+ end
39
+
40
+ def satisfied?(invocations_so_far)
41
+ invocations_so_far >= required
42
+ end
43
+
44
+ def needs_verifying?
45
+ !allowed_any_number_of_times?
46
+ end
47
+
48
+ def verified?(invocation_count)
49
+ (invocation_count >= required) && (invocation_count <= maximum)
50
+ end
51
+
52
+ def allowed_any_number_of_times?
53
+ required == 0 && infinite?(maximum)
54
+ end
55
+
56
+ def used?(invocation_count)
57
+ (invocation_count > 0) || (maximum == 0)
58
+ end
59
+
60
+ def mocha_inspect
61
+ if allowed_any_number_of_times?
62
+ "allowed any number of times"
63
+ else
64
+ if required == 0 && maximum == 0
65
+ "expected never"
66
+ elsif required == maximum
67
+ "expected exactly #{times(required)}"
68
+ elsif infinite?(maximum)
69
+ "expected at least #{times(required)}"
70
+ elsif required == 0
71
+ "expected at most #{times(maximum)}"
72
+ else
73
+ "expected between #{required} and #{times(maximum)}"
74
+ end
75
+ end
76
+ end
77
+
78
+ protected
79
+
80
+ attr_reader :required, :maximum
81
+
82
+ def times(number)
83
+ number == 1 ? "once" : "#{number} times"
84
+ end
85
+
86
+ def infinite?(number)
87
+ number.respond_to?(:infinite?) && number.infinite?
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -11,18 +11,10 @@ module Mocha
11
11
  def stub(method)
12
12
  unless stubba_methods.include?(method)
13
13
  method.stub
14
- stubba_methods.push method
14
+ stubba_methods.push(method)
15
15
  end
16
16
  end
17
17
 
18
- def verify_all(&block)
19
- unique_mocks.each { |mock| mock.verify(&block) }
20
- end
21
-
22
- def unique_mocks
23
- stubba_methods.inject({}) { |mocks, method| mocks[method.mock.__id__] = method.mock; mocks }.values
24
- end
25
-
26
18
  def unstub_all
27
19
  while stubba_methods.length > 0
28
20
  method = stubba_methods.pop
@@ -0,0 +1,19 @@
1
+ module Mocha
2
+
3
+ class ChangeStateSideEffect
4
+
5
+ def initialize(state)
6
+ @state = state
7
+ end
8
+
9
+ def perform
10
+ @state.activate
11
+ end
12
+
13
+ def mocha_inspect
14
+ "then #{@state.mocha_inspect}"
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -26,19 +26,31 @@ module Mocha
26
26
  end
27
27
 
28
28
  def hide_original_method
29
- stubbee.__metaclass__.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.__metaclass__.method_defined?(method)
29
+ if method_exists?(method)
30
+ begin
31
+ stubbee.__metaclass__.class_eval("alias_method :#{hidden_method}, :#{method}", __FILE__, __LINE__)
32
+ rescue NameError
33
+ # deal with nasties like ActiveRecord::Associations::AssociationProxy
34
+ end
35
+ end
30
36
  end
31
37
 
32
38
  def define_new_method
33
- stubbee.__metaclass__.class_eval "def #{method}(*args, &block); mocha.method_missing(:#{method}, *args, &block); end"
39
+ stubbee.__metaclass__.class_eval("def #{method}(*args, &block); mocha.method_missing(:#{method}, *args, &block); end", __FILE__, __LINE__)
34
40
  end
35
41
 
36
42
  def remove_new_method
37
- stubbee.__metaclass__.class_eval "remove_method :#{method}"
43
+ stubbee.__metaclass__.class_eval("remove_method :#{method}", __FILE__, __LINE__)
38
44
  end
39
45
 
40
46
  def restore_original_method
41
- stubbee.__metaclass__.class_eval "alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}" if stubbee.__metaclass__.method_defined?(hidden_method)
47
+ if method_exists?(hidden_method)
48
+ begin
49
+ stubbee.__metaclass__.class_eval("alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}", __FILE__, __LINE__)
50
+ rescue NameError
51
+ # deal with nasties like ActiveRecord::Associations::AssociationProxy
52
+ end
53
+ end
42
54
  end
43
55
 
44
56
  def hidden_method
@@ -52,7 +64,7 @@ module Mocha
52
64
 
53
65
  def eql?(other)
54
66
  return false unless (other.class == self.class)
55
- (stubbee == other.stubbee) and (method == other.method)
67
+ (stubbee.object_id == other.stubbee.object_id) and (method == other.method)
56
68
  end
57
69
 
58
70
  alias_method :==, :eql?
@@ -60,6 +72,14 @@ module Mocha
60
72
  def to_s
61
73
  "#{stubbee}.#{method}"
62
74
  end
75
+
76
+ def method_exists?(method)
77
+ existing_methods = []
78
+ existing_methods += stubbee.public_methods(true) - stubbee.superclass.public_methods(true)
79
+ existing_methods += stubbee.protected_methods(true) - stubbee.superclass.protected_methods(true)
80
+ existing_methods += stubbee.private_methods(true) - stubbee.superclass.private_methods(true)
81
+ existing_methods.any? { |m| m.to_s == method.to_s }
82
+ end
63
83
 
64
84
  end
65
85