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

Strict negated predicate matchers #1487

Closed
marcandre opened this issue Oct 7, 2024 · 2 comments
Closed

Strict negated predicate matchers #1487

marcandre opened this issue Oct 7, 2024 · 2 comments

Comments

@marcandre
Copy link
Contributor

marcandre commented Oct 7, 2024

Negated Predicate Matchers should be strict.

I just realized that negated predicate matchers are not strict, i.e. expect(something).not_to be_foo will pass if foo? returns nil. We have a bunch of these mistakes in rubocop and in rubocop-ast.

I believe it should fail. To be correct, methods ending with ? should typically not return nil. It's quite easy to return nil without wanting to. It's also easy to not realize a method if returning nil (e.g. if x.foo?), but sometimes the nil and false might be treated differently (often without meaning too) and subtle bugs can be introduced.

It may be advisable for compatibility's sake to put that under a flag. I believe that flag should default to strict although that may have to wait for a major version (if ever?).

Note that the only other choice given to rspec user is quite ugly, in particular:

# currently not strict enough version
it_is_expected.not_to be_foo
# correct version
expect(subject.foo?).to be false

Your environment

  • rspec-expectations version: 3.13.3
@JonRowe
Copy link
Member

JonRowe commented Oct 8, 2024

Can you double check you've turned on the existing strict predicate check?
e.g RSpec::Expectations.configuration.strict_predicate_matchers = false

As a quick check shows this to be working as expected for me, we have specs covering it by implementation and adding an exact one passes:

    it "fails when #sym? returns nil" do
      actual = double("actual", :foo? => nil)
      expect {
        expect(actual).not_to be_foo
      }.to fail_with("expected `#{actual.inspect}.foo?` to return false, got nil")
    end

@marcandre
Copy link
Contributor Author

I have such a bad memory 🤦‍♂️
#1102

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants