rspec / rspec-expectations

Provides a readable API to express expected outcomes of a code example
https://rspec.info
MIT License
1.26k stars 397 forks source link

Unexpected behaviour using `include` matcher with Time and iso8601 timestamps #1211

Closed bobf closed 4 years ago

bobf commented 4 years ago

When using the include matcher to compare instances of Time and Time#iso8601 I get inconsistent results depending on whether Rails has been loaded:

# Fails:
it do
  time = Time.new(2000, 1, 1, 0, 0, 0)
  expect([time.iso8601]).to include(time)
end

# Passes:
it do
  require 'rails'
  time = Time.new(2000, 1, 1, 0, 0, 0)
  expect([time.iso8601]).to include(time)
end

However this is not consistent with either the eq or eql matchers. Is this intended behaviour ? It seems like a false positive to me.

I have made a repository to demonstrate the issue here: https://github.com/bobf/rspec_rails_time_comparison_example

Steps to reproduce:

git clone https://github.com/bobf/rspec_rails_time_comparison_example.git
cd rspec_rails_time_comparison_example
bundle install
bundle exec rspec
bobf commented 4 years ago

After doing a bit more digging it seems that this is just weird Rails semantics:

irb(main):001:0> require 'time'
=> true
irb(main):002:0> time = Time.new(2000, 1, 1, 1, 0, 0)
irb(main):003:0> [time.iso8601].include?(time)
=> false
irb(main):004:0> [time].include?(time.iso8601)
=> false
irb(main):005:0> require 'rails'
=> true
irb(main):006:0> [time].include?(time.iso8601)
=> true
irb(main):007:0> [time.iso8601].include?(time)
=> false
irb(main):008:0> time.iso8601 == time
=> false
irb(main):009:0> time == time.iso8601
=> true

Closing ticket.

JonRowe commented 4 years ago

Rails monkey patches a lot of core Ruby in order to provide various conveniences, and the include matcher pretty much delegates to the Ruby include? behaviour.

JonRowe commented 4 years ago

Transferred to the correct repo to help future travellers

bobf commented 4 years ago

@JonRowe Ah, thank you - appreciated.