Created
September 22, 2009 16:22
-
-
Save bcardarella/191210 to your computer and use it in GitHub Desktop.
Should Have Named Scope matcher for Rspec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Shoulda # :nodoc: | |
module ActiveRecord # :nodoc: | |
# Examples: | |
# class Book < ActiveRecord::Base | |
# named_scope :test, :conditions => { :name => "test" } | |
# named_scope :by_name, lambda { |n| { :conditions => { :name => n} } } | |
# end | |
# | |
# RSpec: | |
# describe Book | |
# describe "Named Scope" do | |
# before(:each) do | |
# @expected = [Factory(:book, :name => "test")] | |
# Factory(:book, :name => "blah") | |
# Factory(:book, :name => "heynow") | |
# @by_test_param = "test" | |
# end | |
# | |
# it { should have_named_scope(:test).to_return(@expected) } | |
# it { should have_named_scope("by_name(@by_test_param)").to_return(@expected) } | |
# end | |
# end | |
# | |
# Test::Unit: | |
# class BookTest < ActiveSupport::TestCase | |
# context "Named Scope" do | |
# setup do | |
# @expected = [Factory(:book, :name => "test")] | |
# Factory(:book, :name => "blah") | |
# Factory(:book, :name => "heynow") | |
# @by_test_param = "test" | |
# end | |
# | |
# should_have_named_scope(:test, "@expected") | |
# should_have_named_scope("by_name(@by_test_param)", "@expected") | |
# end | |
# end | |
module NamedScopeMatcher | |
def have_named_scope(scope_call) | |
HaveNamedScopeMatcher.new(scope_call).in_context(self) | |
end | |
class HaveNamedScopeMatcher | |
def initialize(scope_call) | |
@scope_call = scope_call | |
end | |
def matches?(subject) | |
@subject = subject.class | |
if @expected | |
return is_named_scope? && match_expected? | |
else | |
return is_named_scope? | |
end | |
end | |
def to_return(expected) | |
@expected = get_expected(expected) | |
self | |
end | |
def in_context(context) | |
@context = context | |
self | |
end | |
def failure_message | |
if @not_named_scope | |
@not_named_scope | |
else | |
"Named scope failed for #{@subject.class.name}.#{@scope_call}\n" + | |
"Expected: #{@expected.inspect}\n" + | |
"Got: #{@result.inspect}" | |
end | |
end | |
def description(scope_call = nil, expected = nil, subject = nil) | |
@scope_call ||= scope_call | |
@expected ||= expected | |
@subject ||= subject | |
message = "have #{@subject}.#{@scope_call}" | |
message = "#{message} result in #{@expected.inspect}" if @expected | |
return message | |
end | |
private | |
def is_named_scope? | |
scope_sym = @scope_call.to_s.split("(").first.to_sym | |
if @subject.scopes.key?(scope_sym) | |
return true | |
else | |
@not_named_scope = "Named scope '#{scope_sym}' does not exist for #{@subject}" | |
return false | |
end | |
end | |
def match_expected? | |
@result = @context.instance_eval("#{@subject}.#{@scope_call}") | |
@result == @expected | |
end | |
def get_expected(expectation) | |
if expectation.is_a?(String) | |
return @context.instance_eval(expectation) | |
else | |
return expectation | |
end | |
end | |
end | |
end | |
module NamedScopeMacro | |
include NamedScopeMatcher | |
def should_have_named_scope(scope_call, expected = nil) | |
subject = (described_type rescue model_class).new | |
matcher = HaveNamedScopeMatcher.new(scope_call) | |
should matcher.description(scope_call, expected, subject.class) do | |
assert matcher.in_context(self).to_return(expected).matches?(subject), | |
matcher.failure_message | |
end | |
end | |
end | |
end | |
end | |
if defined? Spec | |
Spec::Runner.configure do |config| | |
config.include(Shoulda::ActiveRecord::NamedScopeMatcher) | |
end | |
else | |
Test::Unit::TestCase.class_eval { extend Shoulda::ActiveRecord::NamedScopeMacro } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment