From c6b1043e9d1b7fe9912c330b6e7d4342f2a9694e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=99=88=20=20jacopo=20beschi=20=F0=9F=99=89?= Date: Wed, 18 Apr 2018 09:19:40 +0000 Subject: Resolve "Make a Rubocop that forbids returning from a block" --- .../cop/avoid_break_from_strong_memoize_spec.rb | 74 ++++++++++++ spec/rubocop/cop/avoid_return_from_blocks_spec.rb | 127 +++++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb create mode 100644 spec/rubocop/cop/avoid_return_from_blocks_spec.rb (limited to 'spec/rubocop') diff --git a/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb b/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb new file mode 100644 index 00000000000..ac7b1575ec0 --- /dev/null +++ b/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../rubocop/cop/avoid_break_from_strong_memoize' + +describe RuboCop::Cop::AvoidBreakFromStrongMemoize do + include CopHelper + + subject(:cop) { described_class.new } + + it 'flags violation for break inside strong_memoize' do + expect_offense(<<~RUBY) + strong_memoize(:result) do + break if something + ^^^^^ Do not use break inside strong_memoize, use next instead. + + do_an_heavy_calculation + end + RUBY + end + + it 'flags violation for break inside strong_memoize nested blocks' do + expect_offense(<<~RUBY) + strong_memoize do + items.each do |item| + break item + ^^^^^^^^^^ Do not use break inside strong_memoize, use next instead. + end + end + RUBY + end + + it "doesn't flag violation for next inside strong_memoize" do + expect_no_offenses(<<~RUBY) + strong_memoize(:result) do + next if something + + do_an_heavy_calculation + end + RUBY + end + + it "doesn't flag violation for break inside blocks" do + expect_no_offenses(<<~RUBY) + call do + break if something + + do_an_heavy_calculation + end + RUBY + end + + it "doesn't call add_offense twice for nested blocks" do + source = <<~RUBY + call do + strong_memoize(:result) do + break if something + + do_an_heavy_calculation + end + end + RUBY + expect_any_instance_of(described_class).to receive(:add_offense).once + + inspect_source(source) + end + + it "doesn't check when block is empty" do + expect_no_offenses(<<~RUBY) + strong_memoize(:result) do + end + RUBY + end +end diff --git a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb new file mode 100644 index 00000000000..a5c280a7adc --- /dev/null +++ b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb @@ -0,0 +1,127 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../rubocop/cop/avoid_return_from_blocks' + +describe RuboCop::Cop::AvoidReturnFromBlocks do + include CopHelper + + subject(:cop) { described_class.new } + + it 'flags violation for return inside a block' do + expect_offense(<<~RUBY) + call do + do_something + return if something_else + ^^^^^^ Do not return from a block, use next or break instead. + end + RUBY + end + + it "doesn't call add_offense twice for nested blocks" do + source = <<~RUBY + call do + call do + something + return if something_else + end + end + RUBY + expect_any_instance_of(described_class).to receive(:add_offense).once + + inspect_source(source) + end + + it 'flags violation for return inside included > def > block' do + expect_offense(<<~RUBY) + included do + def a_method + return if something + + call do + return if something_else + ^^^^^^ Do not return from a block, use next or break instead. + end + end + end + RUBY + end + + shared_examples 'examples with whitelisted method' do |whitelisted_method| + it "doesn't flag violation for return inside #{whitelisted_method}" do + expect_no_offenses(<<~RUBY) + items.#{whitelisted_method} do |item| + do_something + return if something_else + end + RUBY + end + end + + %i[each each_filename times loop].each do |whitelisted_method| + it_behaves_like 'examples with whitelisted method', whitelisted_method + end + + shared_examples 'examples with def methods' do |def_method| + it "doesn't flag violation for return inside #{def_method}" do + expect_no_offenses(<<~RUBY) + helpers do + #{def_method} do + return if something + + do_something_more + end + end + RUBY + end + end + + %i[define_method lambda].each do |def_method| + it_behaves_like 'examples with def methods', def_method + end + + it "doesn't flag violation for return inside a lambda" do + expect_no_offenses(<<~RUBY) + lambda do + do_something + return if something_else + end + RUBY + end + + it "doesn't flag violation for return used inside a method definition" do + expect_no_offenses(<<~RUBY) + describe Klass do + def a_method + do_something + return if something_else + end + end + RUBY + end + + it "doesn't flag violation for next inside a block" do + expect_no_offenses(<<~RUBY) + call do + do_something + next if something_else + end + RUBY + end + + it "doesn't flag violation for break inside a block" do + expect_no_offenses(<<~RUBY) + call do + do_something + break if something_else + end + RUBY + end + + it "doesn't check when block is empty" do + expect_no_offenses(<<~RUBY) + call do + end + RUBY + end +end -- cgit v1.2.1