From ea7600d75e3a1f256cd5bef788b94e4ae7fc6d21 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Thu, 27 Jul 2017 12:19:44 +0200 Subject: [PATCH] Implement #guard and #guard_not to combine guards * Closes ruby/mspec#30 --- lib/mspec/guards/guard.rb | 28 ++++- spec/guards/guard_spec.rb | 210 +++++++++++++++++++++++++++++++++++ spec/guards/platform_spec.rb | 14 +++ spec/guards/version_spec.rb | 7 ++ 4 files changed, 257 insertions(+), 2 deletions(-) diff --git a/lib/mspec/guards/guard.rb b/lib/mspec/guards/guard.rb index 88adbba2..322a0814 100644 --- a/lib/mspec/guards/guard.rb +++ b/lib/mspec/guards/guard.rb @@ -76,14 +76,22 @@ def yield?(invert = false) def run_if(name, &block) @name = name - yield if yield?(false) + if block + yield if yield?(false) + else + yield?(false) + end ensure unregister end def run_unless(name, &block) @name = name - yield if yield?(true) + if block + yield if yield?(true) + else + yield?(true) + end ensure unregister end @@ -115,3 +123,19 @@ def match? raise "must be implemented by the subclass" end end + +# Combined guards + +def guard(condition, &block) + raise "condition must be a Proc" unless condition.is_a?(Proc) + raise LocalJumpError, "no block given" unless block + return yield if MSpec.mode? :unguarded or MSpec.mode? :verify or MSpec.mode? :report + yield if condition.call +end + +def guard_not(condition, &block) + raise "condition must be a Proc" unless condition.is_a?(Proc) + raise LocalJumpError, "no block given" unless block + return yield if MSpec.mode? :unguarded or MSpec.mode? :verify or MSpec.mode? :report + yield unless condition.call +end diff --git a/spec/guards/guard_spec.rb b/spec/guards/guard_spec.rb index 31f9ef96..f2828dd4 100644 --- a/spec/guards/guard_spec.rb +++ b/spec/guards/guard_spec.rb @@ -195,6 +195,23 @@ @guard.stub(:match?).and_return(false) @guard.run_if(:name) { fail } end + + it "returns the result of the block if match? is true" do + @guard.stub(:match?).and_return(true) + @guard.run_if(:name) { 42 }.should == 42 + end + + it "returns nil if given a block and match? is false" do + @guard.stub(:match?).and_return(false) + @guard.run_if(:name) { 42 }.should == nil + end + + it "returns what #match? returns when no block is given" do + @guard.stub(:match?).and_return(true) + @guard.run_if(:name).should == true + @guard.stub(:match?).and_return(false) + @guard.run_if(:name).should == false + end end describe SpecGuard, ".run_unless" do @@ -213,4 +230,197 @@ @guard.stub(:match?).and_return(true) @guard.run_unless(:name) { fail } end + + it "returns the result of the block if match? is false" do + @guard.stub(:match?).and_return(false) + @guard.run_unless(:name) { 42 }.should == 42 + end + + it "returns nil if given a block and match? is true" do + @guard.stub(:match?).and_return(true) + @guard.run_unless(:name) { 42 }.should == nil + end + + it "returns the opposite of what #match? returns when no block is given" do + @guard.stub(:match?).and_return(true) + @guard.run_unless(:name).should == false + @guard.stub(:match?).and_return(false) + @guard.run_unless(:name).should == true + end +end + +describe Object, "#guard" do + before :each do + ScratchPad.clear + end + + after :each do + MSpec.clear_modes + end + + it "allows to combine guards" do + guard1 = VersionGuard.new 'x.x.x' + VersionGuard.stub(:new).and_return(guard1) + guard2 = PlatformGuard.new :dummy + PlatformGuard.stub(:new).and_return(guard2) + + guard1.stub(:match?).and_return(true) + guard2.stub(:match?).and_return(true) + guard -> { ruby_version_is "2.4" and platform_is :linux } do + ScratchPad.record :yield + end + ScratchPad.recorded.should == :yield + + guard1.stub(:match?).and_return(false) + guard2.stub(:match?).and_return(true) + guard -> { ruby_version_is "2.4" and platform_is :linux } do + fail + end + + guard1.stub(:match?).and_return(true) + guard2.stub(:match?).and_return(false) + guard -> { ruby_version_is "2.4" and platform_is :linux } do + fail + end + + guard1.stub(:match?).and_return(false) + guard2.stub(:match?).and_return(false) + guard -> { ruby_version_is "2.4" and platform_is :linux } do + fail + end + end + + it "yields when the Proc returns true" do + guard -> { true } do + ScratchPad.record :yield + end + ScratchPad.recorded.should == :yield + end + + it "does not yield when the Proc returns false" do + guard -> { false } do + fail + end + end + + it "yields if MSpec.mode?(:unguarded) is true" do + MSpec.register_mode :unguarded + + guard -> { false } do + ScratchPad.record :yield1 + end + ScratchPad.recorded.should == :yield1 + + guard -> { true } do + ScratchPad.record :yield2 + end + ScratchPad.recorded.should == :yield2 + end + + it "yields if MSpec.mode?(:verify) is true" do + MSpec.register_mode :verify + + guard -> { false } do + ScratchPad.record :yield1 + end + ScratchPad.recorded.should == :yield1 + + guard -> { true } do + ScratchPad.record :yield2 + end + ScratchPad.recorded.should == :yield2 + end + + it "yields if MSpec.mode?(:report) is true" do + MSpec.register_mode :report + + guard -> { false } do + ScratchPad.record :yield1 + end + ScratchPad.recorded.should == :yield1 + + guard -> { true } do + ScratchPad.record :yield2 + end + ScratchPad.recorded.should == :yield2 + end + + it "raises an error if no Proc is given" do + -> { guard :foo }.should raise_error(RuntimeError) + end + + it "requires a block" do + -> { + guard(-> { true }) + }.should raise_error(LocalJumpError) + -> { + guard(-> { false }) + }.should raise_error(LocalJumpError) + end +end + +describe Object, "#guard_not" do + before :each do + ScratchPad.clear + end + + it "allows to combine guards" do + guard1 = VersionGuard.new 'x.x.x' + VersionGuard.stub(:new).and_return(guard1) + guard2 = PlatformGuard.new :dummy + PlatformGuard.stub(:new).and_return(guard2) + + guard1.stub(:match?).and_return(true) + guard2.stub(:match?).and_return(true) + guard_not -> { ruby_version_is "2.4" and platform_is :linux } do + fail + end + + guard1.stub(:match?).and_return(false) + guard2.stub(:match?).and_return(true) + guard_not -> { ruby_version_is "2.4" and platform_is :linux } do + ScratchPad.record :yield1 + end + ScratchPad.recorded.should == :yield1 + + guard1.stub(:match?).and_return(true) + guard2.stub(:match?).and_return(false) + guard_not -> { ruby_version_is "2.4" and platform_is :linux } do + ScratchPad.record :yield2 + end + ScratchPad.recorded.should == :yield2 + + guard1.stub(:match?).and_return(false) + guard2.stub(:match?).and_return(false) + guard_not -> { ruby_version_is "2.4" and platform_is :linux } do + ScratchPad.record :yield3 + end + ScratchPad.recorded.should == :yield3 + end + + it "yields when the Proc returns false" do + guard_not -> { false } do + ScratchPad.record :yield + end + ScratchPad.recorded.should == :yield + end + + it "does not yield when the Proc returns true" do + guard_not -> { true } do + fail + end + end + + it "raises an error if no Proc is given" do + -> { guard_not :foo }.should raise_error(RuntimeError) + end + + it "requires a block" do + -> { + guard_not(-> { true }) + }.should raise_error(LocalJumpError) + -> { + guard_not(-> { false }) + }.should raise_error(LocalJumpError) + end end diff --git a/spec/guards/platform_spec.rb b/spec/guards/platform_spec.rb index cf1249c4..749963d3 100644 --- a/spec/guards/platform_spec.rb +++ b/spec/guards/platform_spec.rb @@ -20,6 +20,13 @@ ScratchPad.recorded.should == :yield end + it "returns what #os? returns when no block is given" do + PlatformGuard.stub(:os?).and_return(true) + platform_is(:solarce).should == true + PlatformGuard.stub(:os?).and_return(false) + platform_is(:solarce).should == false + end + it "sets the name of the guard to :platform_is" do platform_is(:solarce) { } @guard.name.should == :platform_is @@ -53,6 +60,13 @@ ScratchPad.recorded.should == :yield end + it "returns the opposite of what #os? returns when no block is given" do + PlatformGuard.stub(:os?).and_return(true) + platform_is_not(:solarce).should == false + PlatformGuard.stub(:os?).and_return(false) + platform_is_not(:solarce).should == true + end + it "sets the name of the guard to :platform_is_not" do platform_is_not(:solarce) { } @guard.name.should == :platform_is_not diff --git a/spec/guards/version_spec.rb b/spec/guards/version_spec.rb index f11e3dbd..07eb451e 100644 --- a/spec/guards/version_spec.rb +++ b/spec/guards/version_spec.rb @@ -68,6 +68,13 @@ ScratchPad.recorded.should_not == :yield end + it "returns what #match? returns when no block is given" do + @guard.stub(:match?).and_return(true) + ruby_version_is('x.x.x').should == true + @guard.stub(:match?).and_return(false) + ruby_version_is('x.x.x').should == false + end + it "sets the name of the guard to :ruby_version_is" do ruby_version_is("") { } @guard.name.should == :ruby_version_is