Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make be_predicate fail upon calling a private method #207

Merged
merged 10 commits into from May 30, 2013
Merged
24 changes: 24 additions & 0 deletions features/built_in_matchers/predicates.feature
Expand Up @@ -42,6 +42,10 @@ Feature: predicate matchers

`expected zero? to return true, got false`

Calling private methods will also fail:

`expected private_method? to return true but it's a private method`

Any arguments passed to the matcher will be passed on to the predicate method.

Scenario: should be_zero (based on Fixnum#zero?)
Expand Down Expand Up @@ -135,3 +139,23 @@ Feature: predicate matchers
And the output should contain "expected multiple_of?(4) to return false, got true"
And the output should contain "expected multiple_of?(5) to return true, got false"

Scenario: calling private method causes error
Given a file named "attempting_to_match_private_method_spec.rb" with:
"""ruby
class WithPrivateMethods
def secret?
true
end
private :secret?
end

describe 'private methods' do
subject { WithPrivateMethods.new }

# deliberate failure
it { should be_secret }
end
"""
When I run `rspec attempting_to_match_private_method_spec.rb`
Then the output should contain "1 example, 1 failure"
And the output should contain "expectation set on private method `secret?`"
16 changes: 16 additions & 0 deletions lib/rspec/matchers/built_in/be.rb
Expand Up @@ -135,6 +135,11 @@ def initialize(*args, &block)

def matches?(actual)
@actual = actual

if is_private_on?( @actual )
raise Expectations::ExpectationNotMetError.new("expectation set on private method `#{predicate}`")
end

begin
return @result = actual.__send__(predicate, *@args, &@block)
rescue NameError => predicate_missing_error
Expand Down Expand Up @@ -162,6 +167,17 @@ def description

private

# support 187
if methods.first.is_a? String
def is_private_on? actual
actual.private_methods.include? predicate.to_s
end
else
def is_private_on? actual
actual.private_methods.include? predicate
end
end

def predicate
"#{@expected}?".to_sym
end
Expand Down
12 changes: 12 additions & 0 deletions spec/rspec/matchers/be_spec.rb
Expand Up @@ -31,6 +31,18 @@
}.to raise_error(NameError, /happy\?/)
end

it 'fails when :predicate? is private' do
klass = Class.new do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for grins: I'd name this class privately_happy and have happy? return true :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On your head be it... ;) I totally did not indulge my own humour in the commit message...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

private
def happy?
false
end
end
expect {
expect(klass.new).to be_happy
}.to raise_error
end

it "fails on error other than NameError" do
actual = double("actual")
actual.should_receive(:foo?).and_raise("aaaah")
Expand Down