Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: rspec/rspec-mocks
...
head fork: rspec/rspec-mocks
  • 13 commits
  • 14 files changed
  • 0 commit comments
  • 7 contributors
Commits on Jul 10, 2012
@ugisozols ugisozols Add missing 'be's to the README. 5288070
@justinko justinko Merge pull request #161 from ugisozols/master
Add missing 'be's to the README.
d9169ca
Commits on Jul 11, 2012
@myronmarston myronmarston Fix ruby warnings.
- lib/rspec/mocks/error_generator.rb:32: warning: assigned but unused variable - expected_args
- lib/rspec/mocks/error_generator.rb:33: warning: assigned but unused variable - actual_args
- lib/rspec/mocks/stub_const.rb:8: warning: shadowing outer local variable - name
- lib/rspec/mocks/stub_const.rb:12: warning: shadowing outer local variable - name
- spec/rspec/mocks/stub_const_spec.rb:60: warning: assigned but unused variable - orig_value
- lib/rspec/mocks/stub_const.rb:233: warning: instance variable @registered_with_mocks_space not initialized


Closes #162.
f36ad4d
Commits on Aug 01, 2012
@dchelimsky dchelimsky Don't modify dup on classes that don't support dup
Fixes #168.
b828604
Commits on Aug 03, 2012
@daneget daneget Fix any_instance to handle methods defined on superclasses.
Previously, the recorder implementation created a SystemStackError.

Closes #152.
1272c8a
@myronmarston myronmarston Cleanup spec a bit. 306ee36
@myronmarston myronmarston Update changelog. f1a2682
Commits on Aug 05, 2012
@dchelimsky dchelimsky align the feature READMEs for stubs and message expectations e2826c6
@dchelimsky dchelimsky dev: update optional dev dependencies 37e095c
Commits on Aug 10, 2012
@jredville jredville fix formatting for relish df607ea
@alindeman alindeman Merge pull request #173 from jredville/master
Clean up formatting for Relish
bb21bc1
Commits on Aug 11, 2012
@myronmarston myronmarston Fix use of const_defined? and const_get so it ignores top-level const…
…ants.

I didn't realize this previously, but these methods can pick up a top-level
constant when you don't intend it (e.g. ::Hash when checking MyGem.const_defined?("Hash")).
deec990
Commits on Aug 12, 2012
@myronmarston myronmarston 2.11.2 release. e7bd234
View
14 Changelog.md
@@ -1,3 +1,15 @@
+### 2.11.2 / 2012-08-11
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.11.1...v2.11.2)
+
+Bug fixes
+
+* Don't modify `dup` on classes that don't support `dup` (David Chelimsky)
+* Fix `any_instance` so that it works properly with methods defined on
+ a superclass. (Daniel Eguzkiza)
+* Fix `stub_const` so that it works properly for nested constants that
+ share a name with a top-level constant (e.g. "MyGem::Hash"). (Myron
+ Marston)
+
### 2.11.1 / 2012-07-09
[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.11.0...v2.11.1)
@@ -13,7 +25,7 @@ Bug fixes
Enhancements
-* expose ArgumentListMatcher as a formal API
+* Expose ArgumentListMatcher as a formal API
* supports use by 3rd party mock frameworks like Surrogate
* Add `stub_const` API to stub constants for the duration of an
example (Myron Marston).
View
4 Gemfile-custom.sample
@@ -1,12 +1,12 @@
group :development do
gem 'interactive_rspec'
- gem 'relish', '~> 0.5.0'
+ gem 'relish', '~> 0.6.0'
gem 'guard-rspec', '0.5.0'
gem 'growl', '1.0.3'
gem 'spork', '0.9.0'
platform :mri do
- gem 'rb-fsevent', '~> 0.4.3.1'
+ gem 'rb-fsevent'
gem 'ruby-prof', '~> 0.10.0'
case RUBY_VERSION
View
4 README.md
@@ -152,8 +152,8 @@ specify certain kinds of arguments:
```ruby
double.should_receive(:msg).with(no_args())
double.should_receive(:msg).with(any_args())
-double.should_receive(:msg).with(1, kind_of(Numeric), "b") #2nd argument can any kind of Numeric
-double.should_receive(:msg).with(1, boolean(), "b") #2nd argument can true or false
+double.should_receive(:msg).with(1, kind_of(Numeric), "b") #2nd argument can be any kind of Numeric
+double.should_receive(:msg).with(1, boolean(), "b") #2nd argument can be true or false
double.should_receive(:msg).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
double.should_receive(:msg).with(1, anything(), "b") #2nd argument can be anything at all
double.should_receive(:msg).with(1, duck_type(:abs, :div), "b")
View
20 features/argument_matchers/README.md
@@ -4,20 +4,20 @@ Argument matchers can be used:
* In stubs to constrain the scope of the stubbed method
- obj.stub(:foo).with(:bar) do |arg|
- #do something for :bar
- end
- obj.stub(:foo).with(:baz) do |arg|
- #do something for :baz
- end
+ obj.stub(:foo).with(:bar) do |arg|
+ #do something for :bar
+ end
+ obj.stub(:foo).with(:baz) do |arg|
+ #do something for :baz
+ end
* In expectations to validate the arguments that should be received in a method call
- #create a double
- obj = double()
+ #create a double
+ obj = double()
- #expect a message with given args
- obj.should_receive(:message).with('an argument')
+ #expect a message with given args
+ obj.should_receive(:message).with('an argument')
If more control is needed, one can use a block
View
4 features/argument_matchers/type_matchers.feature
@@ -1,6 +1,8 @@
Feature: stub with argument constraints
- You can further specify the behavior by constraining the type, format and/or number of arguments with the #with() method chained off of #stub()
+ You can further specify the behavior by constraining the type,
+ format and/or number of arguments with the `#with()` method
+ chained off of `#stub()`
Scenario: an_instance_of argument matcher
Given a file named "stub_an_instance_of_args_spec.rb" with:
View
37 features/message_expectations/README.md
@@ -7,7 +7,30 @@
obj.should_receive(:message)
# specify a return value
- obj.should_receive(:message) { 'this is the value to return' }
+ obj.should_receive(:message) { :value }
+ obj.should_receive(:message => :value)
+ obj.should_receive(:message).and_return(:value)
+
+These forms are somewhat interchangeable. The difference is that the
+block contents are evaluated lazily when the `obj` receives the
+`message` message, whereas the others are evaluated as they are read.
+
+### Fake implementation
+
+ obj.should_receive(:message) do |arg1, arg2|
+ # set expectations about the args in this block
+ # and set a return value
+ end
+
+### Raising/Throwing
+
+ obj.should_receive(:message).and_raise("this error")
+ obj.should_receive(:message).and_throw(:this_symbol)
+
+You can also use the block format:
+
+ obj.should_receive(:message) { raise "this error" }
+ obj.should_receive(:message) { throw :this_symbol }
### Argument constraints
@@ -40,19 +63,7 @@
obj.should_receive(:message).at_most(:twice)
obj.should_receive(:message).at_most(n).times
-### Raising/Throwing
-
- obj.should_receive(:message) { raise "this error" }
- obj.should_receive(:message) { throw :this_symbol }
-
### Ordering
obj.should_receive(:one).ordered
obj.should_receive(:two).ordered
-
-### Arbitrary handling
-
- obj.should_receive(:message) do |arg1, arg2|
- # set expectations about the args in this block
- # and set a return value
- end
View
12 features/method_stubs/README.md
@@ -1,12 +1,16 @@
### Stub return values
+ # create a double
+ obj = double()
+
+ # specify a return value
obj.stub(:message) { :value }
obj.stub(:message => :value)
obj.stub(:message).and_return(:value)
-These forms are somewhat interchangeable. The difference is that the block
-contents are evaluated lazily when the `obj` receives the `message` message,
-whereas the others are evaluated as they are read.
+These forms are somewhat interchangeable. The difference is that the
+block contents are evaluated lazily when the `obj` receives the
+`message` message, whereas the others are evaluated as they are read.
### Fake implementation
@@ -20,7 +24,7 @@ whereas the others are evaluated as they are read.
obj.stub(:message).and_raise("this error")
obj.stub(:message).and_throw(:this_symbol)
-You can also use the block format, for consistency with other stubs:
+You can also use the block format:
obj.stub(:message) { raise "this error" }
obj.stub(:message) { throw :this_symbol }
View
2  lib/rspec/mocks/any_instance.rb
@@ -54,7 +54,7 @@ def __recorder
private
def modify_dup_to_remove_mock_proxy_when_invoked
- unless self.method_defined?(:__rspec_original_dup)
+ if self.method_defined?(:dup) and !self.method_defined?(:__rspec_original_dup)
self.class_eval do
def __rspec_dup
__remove_mock_proxy
View
6 lib/rspec/mocks/any_instance/recorder.rb
@@ -175,7 +175,8 @@ def observe!(method_name)
backup_method!(method_name)
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
def #{method_name}(*args, &blk)
- self.class.__recorder.playback!(self, :#{method_name})
+ klass = self.method(:#{method_name}).owner
+ klass.__recorder.playback!(self, :#{method_name})
self.__send__(:#{method_name}, *args, &blk)
end
EOM
@@ -186,7 +187,8 @@ def mark_invoked!(method_name)
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
def #{method_name}(*args, &blk)
method_name = :#{method_name}
- invoked_instance = self.class.__recorder.instance_that_received(method_name)
+ klass = self.method(:#{method_name}).owner
+ invoked_instance = klass.__recorder.instance_that_received(method_name)
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
end
EOM
View
2  lib/rspec/mocks/error_generator.rb
@@ -31,7 +31,7 @@ def raise_unexpected_message_args_error(expectation, *args)
def raise_missing_default_stub_error(expectation,*args)
expected_args = format_args(*expectation.expected_args)
actual_args = args.collect {|a| format_args(*a)}.join(", ")
- __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n Please stub a default value first if message might be received with other args as well. \n"
+ __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}\n Please stub a default value first if message might be received with other args as well. \n"
end
# @private
View
61 lib/rspec/mocks/stub_const.rb
@@ -4,15 +4,54 @@ module Mocks
# constant stubbing.
# @api private
module RecursiveConstMethods
- def recursive_const_get(name)
- name.split('::').inject(Object) { |mod, name| mod.const_get name }
+ # We only want to consider constants that are defined directly on a
+ # particular module, and not include top-level/inherited constants.
+ # Unfortunately, the constant API changed between 1.8 and 1.9, so
+ # we need to conditionally define methods to ignore the top-level/inherited
+ # constants.
+ #
+ # Given `class A; end`:
+ #
+ # On 1.8:
+ # - A.const_get("Hash") # => ::Hash
+ # - A.const_defined?("Hash") # => false
+ # - Neither method accepts the extra `inherit` argument
+ # On 1.9:
+ # - A.const_get("Hash") # => ::Hash
+ # - A.const_defined?("Hash") # => true
+ # - A.const_get("Hash", false) # => raises NameError
+ # - A.const_defined?("Hash", false) # => false
+ if Module.method(:const_defined?).arity == 1
+ def const_defined_on?(mod, const_name)
+ mod.const_defined?(const_name)
+ end
+
+ def get_const_defined_on(mod, const_name)
+ if const_defined_on?(mod, const_name)
+ return mod.const_get(const_name)
+ end
+
+ raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
+ end
+ else
+ def const_defined_on?(mod, const_name)
+ mod.const_defined?(const_name, false)
+ end
+
+ def get_const_defined_on(mod, const_name)
+ mod.const_get(const_name, false)
+ end
+ end
+
+ def recursive_const_get(const_name)
+ const_name.split('::').inject(Object) { |mod, name| get_const_defined_on(mod, name) }
end
- def recursive_const_defined?(name)
- name.split('::').inject([Object, '']) do |(mod, full_name), name|
+ def recursive_const_defined?(const_name)
+ const_name.split('::').inject([Object, '']) do |(mod, full_name), name|
yield(full_name, name) if block_given? && !mod.is_a?(Module)
- return false unless mod.const_defined?(name)
- [mod.const_get(name), [mod, name].join('::')]
+ return false unless const_defined_on?(mod, name)
+ [get_const_defined_on(mod, name), [mod, name].join('::')]
end
end
end
@@ -139,7 +178,7 @@ def to_constant
class DefinedConstantReplacer < BaseStubber
def stub
@context = recursive_const_get(@context_parts.join('::'))
- @original_value = @context.const_get(@const_name)
+ @original_value = get_const_defined_on(@context, @const_name)
constants_to_transfer = verify_constants_to_transfer!
@@ -160,7 +199,7 @@ def rspec_reset
def transfer_nested_constants(constants)
constants.each do |const|
- @stubbed_value.const_set(const, original_value.const_get(const))
+ @stubbed_value.const_set(const, get_const_defined_on(original_value, const))
end
end
@@ -202,9 +241,9 @@ class UndefinedConstantSetter < BaseStubber
def stub
remaining_parts = @context_parts.dup
@deepest_defined_const = @context_parts.inject(Object) do |klass, name|
- break klass unless klass.const_defined?(name)
+ break klass unless const_defined_on?(klass, name)
remaining_parts.shift
- klass.const_get(name)
+ get_const_defined_on(klass, name)
end
context = remaining_parts.inject(@deepest_defined_const) do |klass, name|
@@ -230,7 +269,7 @@ def rspec_reset
#
# @api private
def self.ensure_registered_with_mocks_space
- return if @registered_with_mocks_space
+ return if defined?(@registered_with_mocks_space) && @registered_with_mocks_space
::RSpec::Mocks.space.add(self)
@registered_with_mocks_space = true
end
View
2  lib/rspec/mocks/version.rb
@@ -1,7 +1,7 @@
module RSpec
module Mocks
module Version
- STRING = '2.11.1'
+ STRING = '2.11.2'
end
end
end
View
25 spec/rspec/mocks/any_instance_spec.rb
@@ -818,8 +818,33 @@ class RSpec::SampleRspecTestClass;end
o.some_method
lambda { o.dup.some_method }.should_not raise_error(SystemStackError)
end
+
+ it "doesn't bomb if the object doesn't support `dup`" do
+ klass = Class.new do
+ undef_method :dup
+ end
+ klass.any_instance
+ end
end
+ context "when directed at a method defined on a superclass" do
+ let(:sub_klass) { Class.new(klass) }
+
+ it "stubs the method correctly" do
+ klass.any_instance.stub(:existing_method).and_return("foo")
+ sub_klass.new.existing_method.should == "foo"
+ end
+
+ it "mocks the method correctly" do
+ instance_one = sub_klass.new
+ instance_two = sub_klass.new
+ expect do
+ klass.any_instance.should_receive(:existing_method)
+ instance_one.existing_method
+ instance_two.existing_method
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "The message 'existing_method' was received by #{instance_two.inspect} but has already been received by #{instance_one.inspect}")
+ end
+ end
end
end
end
View
5 spec/rspec/mocks/stub_const_spec.rb
@@ -57,7 +57,6 @@ def change_const_value_to(value)
end
it 'returns the stubbed value' do
- orig_value = const
stub_const(const_name, 7).should eq(7)
end
end
@@ -178,6 +177,10 @@ def change_const_value_to(value)
it_behaves_like "loaded constant stubbing", "TestClass::Nested"
end
+ context 'for an unloaded constant with nested name that matches a top-level constant' do
+ it_behaves_like "unloaded constant stubbing", "TestClass::Hash"
+ end
+
context 'for a loaded deeply nested constant' do
it_behaves_like "loaded constant stubbing", "TestClass::Nested::NestedEvenMore"
end

No commit comments for this range

Something went wrong with that request. Please try again.