On Sunday 19 April 2009, Michael Schuerig wrote:
> In a Rails controller I set the scope on a model class in an around
> filter. I have defined expectations on the model classes, and
> ideally, I would add a further expectation for the scope. Is this
> already possible in some way? How would I go about adding support a
> scope expectation?
I've found a way to duck punch my way into Spec::Mocks::Proxy and
Spec::Mocks::MessageExpectation to check in #matches that a scope
expectation is met. I'm stuck now, because I don't see how to
appropriately report a violated expectation. So far, the invasive
changes to both classes are completely general; the Rails-specifics are
patched in from outside. That's how it should be, of course. Can anyone
suggest how to achieve this for reporting?
I've attached the changes I've made so far.
Michael
--
Michael Schuerig
mailto:[email protected]
http://www.schuerig.de/michael/
diff --git a/lib/spec/rails/extensions.rb b/lib/spec/rails/extensions.rb
index 989dfd5..8f3d767 100644
--- a/lib/spec/rails/extensions.rb
+++ b/lib/spec/rails/extensions.rb
@@ -2,6 +2,7 @@ require 'spec'
require 'spec/rails/extensions/spec/runner/configuration'
require 'spec/rails/extensions/spec/matchers/have'
+require 'spec/rails/extensions/spec/mocks/scope_expectation'
require 'spec/rails/extensions/active_support/test_case'
require 'spec/rails/extensions/active_record/base'
diff --git a/lib/spec/rails/extensions/spec/mocks/error_generator.rb b/lib/spec/rails/extensions/spec/mocks/error_generator.rb
new file mode 100644
index 0000000..6451493
--- /dev/null
+++ b/lib/spec/rails/extensions/spec/mocks/error_generator.rb
@@ -0,0 +1,9 @@
+module Spec # :nodoc:
+ module Mocks # :nodoc:
+ class ErrorGenerator # :nodoc:
+
+ def raise_unexpected_scope_error()
+ end
+ end
+ end
+end
diff --git a/lib/spec/rails/extensions/spec/mocks/scope_expectation.rb b/lib/spec/rails/extensions/spec/mocks/scope_expectation.rb
new file mode 100644
index 0000000..5069fe6
--- /dev/null
+++ b/lib/spec/rails/extensions/spec/mocks/scope_expectation.rb
@@ -0,0 +1,43 @@
+
+require 'spec/mocks/message_expectation'
+
+module Spec #:nodoc:
+ module Mocks #:nodoc:
+
+ class ScopeExpectation
+ def initialize(proxy, expected_scopes)
+ @proxy, @expected_scopes = proxy, expected_scopes
+ end
+ def scope_matches?
+ match = @expected_scopes.all? { |key, scope|
+ actual = @proxy.target.send(:scope, key)
+ ok = actual == scope
+#debugger ### REMOVE
+ $stderr.puts "*** Scope mismatch\nExpected: #{scope.inspect},\nActual: #{actual.inspect}" unless ok
+ ok
+ }
+ match
+ end
+ end
+
+
+ module MessageExpectationScopeExtension
+ def self.included(base)
+ base.send(:alias_method, :matches_without_scope, :matches)
+ base.send(:alias_method, :matches, :matches_with_scope)
+ end
+ def within_scope(expected_scopes)
+ @scope_expectation = ScopeExpectation.new(@proxy, expected_scopes)
+ self
+ end
+ def matches_with_scope(*args, &block)
+ matches_without_scope(*args, &block) &&
+ (!...@scope_expectation || @scope_expectation.scope_matches?)
+ end
+ end
+ end
+end
+
+Spec::Mocks::MessageExpectation.class_eval do
+ include Spec::Mocks::MessageExpectationScopeExtension
+end
diff --git a/spec/spec/rails/mocks/mock_model_spec.rb b/spec/spec/rails/mocks/mock_model_spec.rb
index 72abf4b..8283d89 100644
--- a/spec/spec/rails/mocks/mock_model_spec.rb
+++ b/spec/spec/rails/mocks/mock_model_spec.rb
@@ -101,6 +101,20 @@ describe "mock_model" do
mock_model(MockableModel).as_new_record.to_param.should be(nil)
end
end
-end
+ describe "#within_scope" do
+ before do
+ @find_scope = { :find => { :include => :associated_model } }
+ MockableModel.should_receive(:all).within_scope(@find_scope).and_return([])
+ end
+ it "should fail with an error for the wrong scope" do
+ MockableModel.all
+ end
+ it "should let the correct scope pass" do
+ MockableModel.send(:with_scope, @find_scope) do
+ MockableModel.all
+ end
+ end
+ end
+end
diff --git a/lib/spec/mocks/message_expectation.rb b/lib/spec/mocks/message_expectation.rb
index 5a57a0a..caaa02e 100644
--- a/lib/spec/mocks/message_expectation.rb
+++ b/lib/spec/mocks/message_expectation.rb
@@ -8,10 +8,11 @@ module Spec
attr_accessor :error_generator
protected :error_generator, :error_generator=
- def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={}, &implementation)
+ def initialize(error_generator, expectation_ordering, expected_from, proxy, sym, method_block, expected_received_count=1, opts={}, &implementation)
@error_generator = error_generator
@error_generator.opts = opts
@expected_from = expected_from
+ @proxy = proxy
@sym = sym
@method_block = method_block
@return_block = nil
@@ -313,8 +314,8 @@ module Spec
end
class NegativeMessageExpectation < MessageExpectation
- def initialize(message, expectation_ordering, expected_from, sym, method_block)
- super(message, expectation_ordering, expected_from, sym, method_block, 0)
+ def initialize(message, expectation_ordering, expected_from, proxy, sym, method_block)
+ super(message, expectation_ordering, expected_from, proxy, sym, method_block, 0)
end
def negative_expectation_for?(sym)
diff --git a/lib/spec/mocks/proxy.rb b/lib/spec/mocks/proxy.rb
index c21ca67..11afc3d 100644
--- a/lib/spec/mocks/proxy.rb
+++ b/lib/spec/mocks/proxy.rb
@@ -15,6 +15,8 @@ module Spec
$rspec_mocks.add(nil) unless $rspec_mocks.nil?
end
+ attr_reader :target
+
def initialize(target, name=nil, options={})
@target = target
@name = name
@@ -43,7 +45,7 @@ module Spec
if existing_stub = @stubs.detect {|s| s.sym == sym }
expectation = existing_stub.build_child(expected_from, block_given?? block : nil, 1, opts)
else
- expectation = MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
+ expectation = MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, self, sym, block_given? ? block : nil, 1, opts)
end
@expectations << expectation
@expectations.last
@@ -52,13 +54,13 @@ module Spec
def add_negative_message_expectation(expected_from, sym, &block)
__add sym
warn_if_nil_class sym
- @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
+ @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, self, sym, block_given? ? block : nil)
@expectations.last
end
def add_stub(expected_from, sym, opts={}, &implementation)
__add sym
- @stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, nil, :any, opts, &implementation)
+ @stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, self, sym, nil, :any, opts, &implementation)
@stubs.first
end
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users