{"action":"created","issue":{"url":"https://api.github.com/repos/rspec/rspec-mocks/issues/1016","labels_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/1016/labels{/name}","comments_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/1016/comments","events_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/1016/events","html_url":"https://github.com/rspec/rspec-mocks/issues/1016","id":109620593,"number":1016,"title":"SystemStackError when decoration is involved","user":{"login":"agrimm","id":20378,"avatar_url":"https://avatars.githubusercontent.com/u/20378?v=3","gravatar_id":"","url":"https://api.github.com/users/agrimm","html_url":"https://github.com/agrimm","followers_url":"https://api.github.com/users/agrimm/followers","following_url":"https://api.github.com/users/agrimm/following{/other_user}","gists_url":"https://api.github.com/users/agrimm/gists{/gist_id}","starred_url":"https://api.github.com/users/agrimm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agrimm/subscriptions","organizations_url":"https://api.github.com/users/agrimm/orgs","repos_url":"https://api.github.com/users/agrimm/repos","events_url":"https://api.github.com/users/agrimm/events{/privacy}","received_events_url":"https://api.github.com/users/agrimm/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-10-03T12:23:12Z","updated_at":"2015-10-03T22:59:32Z","closed_at":null,"body":"Given the following the RSpec,\r\n\r\n    describe UserDecorator do\r\n      let(:user) { User.new }\r\n      let(:decorated_user) { user.decorate }\r\n    \r\n      describe '#greeting' do\r\n        # Failing spec\r\n        it 'uses DecoratedUser#name' do\r\n          expect(decorated_user).to receive(:name).and_call_original\r\n          decorated_user.greeting\r\n        end\r\n    \r\n        # Successful version\r\n        it 'uses User#name' do\r\n          expect(user).to receive(:name).and_call_original\r\n          decorated_user.greeting\r\n        end\r\n    \r\n        # Also successful, because it's now somehow properly set up\r\n        it 'again uses DecoratedUser#name' do\r\n          expect(decorated_user).to receive(:name).and_call_original\r\n          decorated_user.greeting\r\n        end\r\n      end\r\n    end\r\n\r\nI get the following results\r\n\r\n    Andrew-Grimms-MacBook-Pro:rspec_stack_replication agrimm$ bundle exec rspec\r\n    F..\r\n    \r\n    Failures:\r\n    \r\n      1) UserDecorator#greeting uses DecoratedUser#name\r\n         Failure/Error: decorated_user.greeting\r\n         SystemStackError:\r\n           stack level too deep\r\n         # ./app/decorators/user_decorator.rb:5:in `greeting'\r\n         # ./spec/decorators/user_decorator_spec.rb:11:in `block (3 levels) in <top (required)>'\r\n    \r\n    Finished in 2.98 seconds (files took 1.27 seconds to load)\r\n    3 examples, 1 failure\r\n    \r\n    Failed examples:\r\n    \r\n    rspec ./spec/decorators/user_decorator_spec.rb:9 # UserDecorator#greeting uses DecoratedUser#name\r\n\r\nIt seems that making the decorated object the target of the spec avoided the SystemStackError.\r\n\r\nAlso, once the code is exercised a bit, it seems to work ok. The third test is the same as the first, but it passes (the specs are order dependent in this case).\r\n\r\nI've created an example app to replicate this issue. https://github.com/agrimm/rpsec_stack_replication\r\n\r\nThis involved RSpec 3.3.2, and Draper 2.1.0.\r\n\r\nI tried searching for bugs involving SystemStackError, but they seemed to involve `any_instance_of`, unlike this bug.\r\n\r\nApologies if I'm reporting this on the wrong sub-gem - I assume it's a mocking issue."},"comment":{"url":"https://api.github.com/repos/rspec/rspec-mocks/issues/comments/145296328","html_url":"https://github.com/rspec/rspec-mocks/issues/1016#issuecomment-145296328","issue_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/1016","id":145296328,"user":{"login":"myronmarston","id":49391,"avatar_url":"https://avatars.githubusercontent.com/u/49391?v=3","gravatar_id":"","url":"https://api.github.com/users/myronmarston","html_url":"https://github.com/myronmarston","followers_url":"https://api.github.com/users/myronmarston/followers","following_url":"https://api.github.com/users/myronmarston/following{/other_user}","gists_url":"https://api.github.com/users/myronmarston/gists{/gist_id}","starred_url":"https://api.github.com/users/myronmarston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/myronmarston/subscriptions","organizations_url":"https://api.github.com/users/myronmarston/orgs","repos_url":"https://api.github.com/users/myronmarston/repos","events_url":"https://api.github.com/users/myronmarston/events{/privacy}","received_events_url":"https://api.github.com/users/myronmarston/received_events","type":"User","site_admin":false},"created_at":"2015-10-03T22:59:32Z","updated_at":"2015-10-03T22:59:32Z","body":"Thanks for reporting this!  This is definitely a bug but it's one that's not easily solved.  I boiled it down into a failing spec in c7efa414e88c840fe4824cb011948cc1b3296d69 (just pushed into the `expose-issue-1016` branch).  Here's what's going on, using your reproduction repo as an example:\r\n\r\n1. On [line 10](https://github.com/agrimm/rpsec_stack_replication/blob/1212228e578a441ee1791765c1def5b173bdc4b6/spec/decorators/user_decorator_spec.rb#L10) you do `expect(decorated_user).to receive(:name).and_call_original`.  This causes rspec-mocks to get the original method so that it can later call it.\r\n2. However, draper does not define the delegated methods on the decorator ahead of time -- instead it uses `method_missing` to lazily define them on first use.  That means that when that line runs, there is no original method for rspec-mocks to get.  rspec-mocks handles `method_missing`, though; in this case it [generates a proc in place of the original method](https://github.com/rspec/rspec-mocks/blob/v3.3.2/lib/rspec/mocks/method_double.rb#L27-L29) that, when called, will trigger `method_missing` on the object, replicating the original behavior the object would have had (in theory, at least -- it falls over in this case).\r\n3. Because you've mocked the method, rspec-mocks defines a singleton method on the object that it uses to track the fact the method was called and to delegate to the original method object it stored earlier.\r\n4. On [line 11](https://github.com/agrimm/rpsec_stack_replication/blob/1212228e578a441ee1791765c1def5b173bdc4b6/spec/decorators/user_decorator_spec.rb#L11) you call `greeting` which internally calls `name`.  This is the method that rspec-mocks has defined on your object.\r\n5. The implementation calls the proc we generated earlier, which in turn calls `method_missing` on the object.\r\n6. Draper's `method_missing` implementation defines the method on the decorator class using [`delegate` from active support](https://github.com/drapergem/draper/blob/57a514133bc241e74cc4e8877d014cad4e1f12c6/lib/draper/automatic_delegation.rb#L9).\r\n7. Then draper turns around and attempts to invoke the method it just defined.\r\n8. Because rspec-mocks had defined a singleton method on the object, it takes precedence over the instance method draper just defined, and rspec-mocks method is invoked.\r\n9. rspec-mocks' method again calls the proc that delegates to `method_missing` and the process repeats itself.\r\n\r\nThe basic problem is that `and_call_original`, as currently implemented, is not able to work with objects that implement the method lazily in `method_missing` and then call it.  I've tried a few things but haven't been able to come up with a fix yet."}}