require File.expand_path('../../spec_helper', __FILE__) describe '#mock' do subject { Object.new } it "creates a mock DoubleInjection Double" do mock(subject).foobar(1, 2) {:baz} expect(subject.foobar(1, 2)).to eq :baz end it "mocks via inline call" do mock(subject).to_s {"a value"} expect(subject.to_s).to eq "a value" expect { subject.to_s }.to raise_error(RR::Errors::TimesCalledError) RR.reset end describe ".once.ordered" do it "returns the values in the ordered called" do mock(subject).to_s {"value 1"}.ordered mock(subject).to_s {"value 2"}.twice expect(subject.to_s).to eq "value 1" expect(subject.to_s).to eq "value 2" expect(subject.to_s).to eq "value 2" expect { subject.to_s }.to raise_error(RR::Errors::TimesCalledError) RR.reset end end context "when the subject is a proxy for the object with the defined method" do it "stubs the method on the proxy object" do proxy_target = Class.new {def foobar; :original_foobar; end}.new proxy = Class.new do def initialize(target) @target = target end instance_methods.each do |m| unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'method_missing' alias_method "__blank_slated_#{m}", m undef_method m end end def method_missing(method_name, *args, &block) @target.send(method_name, *args, &block) end end.new(proxy_target) expect(proxy.methods).to match_array(proxy_target.methods) mock(proxy).foobar {:new_foobar} expect(proxy.foobar).to eq :new_foobar end end it 'allows terse chaining' do mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}} expect(subject.first(1).second(2).third(3)).to eq 4 mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}} expect(subject.first(1).second(2).third(3)).to eq 4 mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}} expect(subject.first(1).second(2).third(3)).to eq 4 mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}} expect(subject.first(1).second(2).third(3)).to eq 4 mock(subject).first(1).mock!.second(2).mock!.third(3) {4} expect(subject.first(1).second(2).third(3)).to eq 4 end it 'allows chaining with proxy' do pending "this is failing with a TimesCalledError" find_return_value = Object.new def find_return_value.child :the_child end (class << subject; self; end).class_eval do define_method(:find) do |id| id == '1' ? find_return_value : raise(ArgumentError) end end mock.proxy(subject).find('1').mock.proxy!.child expect(subject.find('1').child).to eq :the_child end it 'allows branched chaining' do mock(subject).first do mock! do |expect| expect.branch1 {mock!.branch11 {11}} expect.branch2 {mock!.branch22 {22}} end end o = subject.first expect(o.branch1.branch11).to eq 11 expect(o.branch2.branch22).to eq 22 end it 'allows chained ordering' do mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once expect(subject.to_s).to eq "value 1" expect(subject.to_s).to eq "value 2" expect(subject.to_s).to eq "value 2" expect(subject.to_s).to eq "value 3" expect { subject.to_s }.to raise_error(RR::Errors::TimesCalledError) RR.reset end it "mocks via block with argument" do mock subject do |c| c.to_s {"a value"} c.to_sym {:crazy} end expect(subject.to_s).to eq "a value" expect(subject.to_sym).to eq :crazy end it "mocks via block without argument" do mock subject do to_s {"a value"} to_sym {:crazy} end expect(subject.to_s).to eq "a value" expect(subject.to_sym).to eq :crazy end it "has wildcard matchers" do mock(subject).foobar( is_a(String), anything, numeric, boolean, duck_type(:to_s), /abc/ ) {"value 1"}.twice expect(subject.foobar( 'hello', Object.new, 99, false, "My String", "Tabcola" )).to eq("value 1") expect { subject.foobar(:failure) }.to raise_error(RR::Errors::DoubleNotFoundError) RR.reset end it "mocks methods without letters" do mock(subject, :==).with(55) subject == 55 expect { subject == 99 }.to raise_error(RR::Errors::DoubleNotFoundError) RR.reset end it "expects a method call to a mock via another mock's block yield only once" do cage = Object.new cat = Object.new mock(cat).miau # should be expected to be called only once mock(cage).find_cat.yields(cat) mock(cage).cats cage.find_cat { |c| c.miau } cage.cats end describe "on class method" do class SampleClass1 def self.hello; "hello!"; end end class SampleClass2 < SampleClass1; end it "can mock" do mock(SampleClass1).hello { "hola!" } expect(SampleClass1.hello).to eq "hola!" end it "does not override subclasses" do mock(SampleClass1).hello { "hi!" } SampleClass1.hello expect(SampleClass2.hello).to eq "hello!" end it "should not get affected from a previous example" do expect(SampleClass2.hello).to eq "hello!" end end # bug #44 describe 'when wrapped in an array that is then flattened' do context 'when the method being mocked is not defined' do it "does not raise an error" do mock(subject).foo subject.foo expect([subject].flatten).to eq [subject] end it "honors a #to_ary that already exists" do subject.instance_eval do def to_ary; []; end end mock(subject).foo subject.foo expect([subject].flatten).to eq [] end end context 'when the method being mocked is defined' do before do subject.instance_eval do def foo; end end end it "does not raise an error" do mock(subject).foo subject.foo expect([subject].flatten).to eq [subject] end it "honors a #to_ary that already exists" do eigen(subject).class_eval do def to_ary; []; end end mock(subject).foo subject.foo expect([subject].flatten).to eq [] end end end end