testdouble / mocktail

🥃 Take your Ruby, and make it a double!

Home Page:https://rubygems.org/gems/mocktail

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Infinite loop when used on objects that define `==`

adam12 opened this issue · comments

I only briefly dug into the cause, but wasn't able to find it. Posting a repro here in case anybody else cares to look.

require "mocktail"

class Foobar < Sequel::Model
  def name
    "Bar"
  end
end

foobar = Mocktail.of(Foobar)
Mocktail.stubs { foobar.name }.with { "Foobar" }
Mocktail.explain(foobar)

Run with sequel mock://sqlite <file.rb>

Output

I, [2021-11-15T02:43:07.555625 #52542]  INFO -- : (0.000001s) SELECT * FROM `foobars` LIMIT 0
/usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/share/determines_matching_calls.rb:4:in `determine': stack level too deep (SystemStackError)
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:11:in `block in find'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `each'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `find'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `find'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing.rb:22:in `satisfaction'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing.rb:12:in `fulfill'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call.rb:16:in `handle'
        from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb:45:in `block (2 levels) in define_double_methods!'
         ... 9981 levels...
        from /usr/local/bundle/gems/sequel-5.50.0/bin/sequel:260:in `each'
        from /usr/local/bundle/gems/sequel-5.50.0/bin/sequel:260:in `<top (required)>'
        from /usr/local/bundle/bin/sequel:23:in `load'
        from /usr/local/bundle/bin/sequel:23:in `<main>'

Thanks for raising this, Adam!

Happy Holidays!

I spent some more time looking at this. It's not necessarily a bug when used with Sequel, but with objects that define their own == method.

require "mocktail"

class Baz
  def name
    "Baz"
  end

  def ==(other)
  end
end

foobar = Mocktail.of(Baz)
Mocktail.stubs { foobar.name }.with { "FoobarBaz" }
Mocktail.explain(foobar)

p foobar.name

Removing == from the list of double methods fixes this, and the tests still pass.

diff --git a/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb b/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb
index fb968a3..b9e3186 100644
--- a/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb
+++ b/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb
@@ -40,7 +40,7 @@ module Mocktail
 
     def define_double_methods!(dry_class, type, instance_methods)
       handles_dry_call = @handles_dry_call
-      instance_methods.each do |method|
+      (instance_methods - [:==]).each do |method|
         dry_class.define_method method, ->(*args, **kwargs, &block) {
           handles_dry_call.handle(Call.new(
             singleton: false,