From 64122b94422e7db0adc0f7bb7e52c1fedbf75085 Mon Sep 17 00:00:00 2001 From: Bill Ruddock Date: Mon, 3 Aug 2020 21:50:45 +0100 Subject: [PATCH] Use new expect_correction in Style N-P Use newer expect_offense and expect_correction in specs for Style cops N-P Merge 'register offense' and 'auto-correct' spec examples where possible. Use single-quoted heredoc for nested_parenthesized_calls_spec line continuation --- spec/rubocop/cop/style/negated_if_spec.rb | 68 +- spec/rubocop/cop/style/negated_unless_spec.rb | 68 +- spec/rubocop/cop/style/negated_while_spec.rb | 38 +- .../rubocop/cop/style/nested_modifier_spec.rb | 111 +- .../style/nested_parenthesized_calls_spec.rb | 21 +- spec/rubocop/cop/style/next_spec.rb | 293 +++-- spec/rubocop/cop/style/nil_comparison_spec.rb | 23 +- spec/rubocop/cop/style/non_nil_check_spec.rb | 58 +- spec/rubocop/cop/style/not_spec.rb | 71 +- .../cop/style/numeric_literal_prefix_spec.rb | 76 +- .../cop/style/numeric_literals_spec.rb | 94 +- .../cop/style/numeric_predicate_spec.rb | 368 +++--- .../cop/style/one_line_conditional_spec.rb | 124 +- spec/rubocop/cop/style/or_assignment_spec.rb | 166 +-- .../cop/style/parallel_assignment_spec.rb | 1008 ++++++++++------- .../parentheses_around_condition_spec.rb | 76 +- .../style/percent_literal_delimiters_spec.rb | 192 +++- .../cop/style/percent_q_literals_spec.rb | 22 +- spec/rubocop/cop/style/perl_backrefs_spec.rb | 26 +- spec/rubocop/cop/style/proc_spec.rb | 17 +- 20 files changed, 1636 insertions(+), 1284 deletions(-) diff --git a/spec/rubocop/cop/style/negated_if_spec.rb b/spec/rubocop/cop/style/negated_if_spec.rb index 74a99a53917..9120b46c9e2 100644 --- a/spec/rubocop/cop/style/negated_if_spec.rb +++ b/spec/rubocop/cop/style/negated_if_spec.rb @@ -21,6 +21,13 @@ some_method if !a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `unless` over `if` for negative conditions. RUBY + + expect_correction(<<~RUBY) + unless a_condition + some_method + end + some_method unless a_condition + RUBY end it 'registers an offense for if with "not" condition' do @@ -32,6 +39,13 @@ some_method if not a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `unless` over `if` for negative conditions. RUBY + + expect_correction(<<~RUBY) + unless a_condition + some_method + end + some_method unless a_condition + RUBY end it 'accepts an if/else with negative condition' do @@ -82,31 +96,14 @@ RUBY end - it 'autocorrects for postfix' do - corrected = autocorrect_source('bar if !foo') - - expect(corrected).to eq 'bar unless foo' - end - - it 'autocorrects by replacing if not with unless' do - corrected = autocorrect_source('something if !x.even?') - expect(corrected).to eq 'something unless x.even?' - end - it 'autocorrects by replacing parenthesized if not with unless' do - corrected = autocorrect_source('something if (!x.even?)') - expect(corrected).to eq 'something unless (x.even?)' - end - - it 'autocorrects for prefix' do - corrected = autocorrect_source(<<~RUBY) - if !foo - end + expect_offense(<<~RUBY) + something if (!x.even?) + ^^^^^^^^^^^^^^^^^^^^^^^ Favor `unless` over `if` for negative conditions. RUBY - expect(corrected).to eq <<~RUBY - unless foo - end + expect_correction(<<~RUBY) + something unless (x.even?) RUBY end end @@ -129,23 +126,16 @@ ^^^^^^^ Favor `unless` over `if` for negative conditions. end RUBY - end - - it 'does not register an offense for postfix' do - expect_no_offenses('foo if !bar') - end - - it 'autocorrects for prefix' do - corrected = autocorrect_source(<<~RUBY) - if !foo - end - RUBY - expect(corrected).to eq <<~RUBY + expect_correction(<<~RUBY) unless foo end RUBY end + + it 'does not register an offense for postfix' do + expect_no_offenses('foo if !bar') + end end describe 'with “postfix” style' do @@ -165,6 +155,10 @@ foo if !bar ^^^^^^^^^^^ Favor `unless` over `if` for negative conditions. RUBY + + expect_correction(<<~RUBY) + foo unless bar + RUBY end it 'does not register an offense for prefix' do @@ -173,12 +167,6 @@ end RUBY end - - it 'autocorrects for postfix' do - corrected = autocorrect_source('bar if !foo') - - expect(corrected).to eq 'bar unless foo' - end end it 'does not blow up for ternary ops' do diff --git a/spec/rubocop/cop/style/negated_unless_spec.rb b/spec/rubocop/cop/style/negated_unless_spec.rb index dd75330693a..f4f94972442 100644 --- a/spec/rubocop/cop/style/negated_unless_spec.rb +++ b/spec/rubocop/cop/style/negated_unless_spec.rb @@ -21,6 +21,13 @@ some_method unless !a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `if` over `unless` for negative conditions. RUBY + + expect_correction(<<~RUBY) + if a_condition + some_method + end + some_method if a_condition + RUBY end it 'registers an offense for unless with "not" condition' do @@ -32,6 +39,13 @@ some_method unless not a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `if` over `unless` for negative conditions. RUBY + + expect_correction(<<~RUBY) + if a_condition + some_method + end + some_method if a_condition + RUBY end it 'accepts an unless/else with negative condition' do @@ -65,31 +79,14 @@ RUBY end - it 'autocorrects for postfix' do - corrected = autocorrect_source('bar unless !foo') - - expect(corrected).to eq 'bar if foo' - end - - it 'autocorrects by replacing unless not with if' do - corrected = autocorrect_source('something unless !x.even?') - expect(corrected).to eq 'something if x.even?' - end - it 'autocorrects by replacing parenthesized unless not with if' do - corrected = autocorrect_source('something unless (!x.even?)') - expect(corrected).to eq 'something if (x.even?)' - end - - it 'autocorrects for prefix' do - corrected = autocorrect_source(<<~RUBY) - unless !foo - end + expect_offense(<<~RUBY) + something unless (!x.even?) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `if` over `unless` for negative conditions. RUBY - expect(corrected).to eq <<~RUBY - if foo - end + expect_correction(<<~RUBY) + something if (x.even?) RUBY end end @@ -112,23 +109,16 @@ ^^^^^^^^^^^ Favor `if` over `unless` for negative conditions. end RUBY - end - - it 'does not register an offense for postfix' do - expect_no_offenses('foo unless !bar') - end - - it 'autocorrects for prefix' do - corrected = autocorrect_source(<<~RUBY) - unless !foo - end - RUBY - expect(corrected).to eq <<~RUBY + expect_correction(<<~RUBY) if foo end RUBY end + + it 'does not register an offense for postfix' do + expect_no_offenses('foo unless !bar') + end end describe 'with “postfix” style' do @@ -148,6 +138,10 @@ foo unless !bar ^^^^^^^^^^^^^^^ Favor `if` over `unless` for negative conditions. RUBY + + expect_correction(<<~RUBY) + foo if bar + RUBY end it 'does not register an offense for prefix' do @@ -156,12 +150,6 @@ end RUBY end - - it 'autocorrects for postfix' do - corrected = autocorrect_source('bar unless !foo') - - expect(corrected).to eq 'bar if foo' - end end it 'does not blow up for ternary ops' do diff --git a/spec/rubocop/cop/style/negated_while_spec.rb b/spec/rubocop/cop/style/negated_while_spec.rb index 95546983ce0..99d5cc36267 100644 --- a/spec/rubocop/cop/style/negated_while_spec.rb +++ b/spec/rubocop/cop/style/negated_while_spec.rb @@ -12,6 +12,13 @@ some_method while !a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `until` over `while` for negative conditions. RUBY + + expect_correction(<<~RUBY) + until a_condition + some_method + end + some_method until a_condition + RUBY end it 'registers an offense for until with exclamation point condition' do @@ -23,6 +30,13 @@ some_method until !a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `while` over `until` for negative conditions. RUBY + + expect_correction(<<~RUBY) + while a_condition + some_method + end + some_method while a_condition + RUBY end it 'registers an offense for while with "not" condition' do @@ -34,6 +48,13 @@ some_method while not a_condition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `until` over `while` for negative conditions. RUBY + + expect_correction(<<~RUBY) + until (a_condition) + some_method + end + some_method until a_condition + RUBY end it 'accepts a while where only part of the condition is negated' do @@ -58,19 +79,28 @@ end it 'autocorrects by replacing while not with until' do - corrected = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) something while !x.even? + ^^^^^^^^^^^^^^^^^^^^^^^^ Favor `until` over `while` for negative conditions. something while(!x.even?) + ^^^^^^^^^^^^^^^^^^^^^^^^^ Favor `until` over `while` for negative conditions. RUBY - expect(corrected).to eq <<~RUBY + + expect_correction(<<~RUBY) something until x.even? something until(x.even?) RUBY end it 'autocorrects by replacing until not with while' do - corrected = autocorrect_source('something until !x.even?') - expect(corrected).to eq 'something while x.even?' + expect_offense(<<~RUBY) + something until !x.even? + ^^^^^^^^^^^^^^^^^^^^^^^^ Favor `while` over `until` for negative conditions. + RUBY + + expect_correction(<<~RUBY) + something while x.even? + RUBY end it 'does not blow up for empty while condition' do diff --git a/spec/rubocop/cop/style/nested_modifier_spec.rb b/spec/rubocop/cop/style/nested_modifier_spec.rb index 3d7b0ec5ef7..a337e0f5083 100644 --- a/spec/rubocop/cop/style/nested_modifier_spec.rb +++ b/spec/rubocop/cop/style/nested_modifier_spec.rb @@ -3,86 +3,110 @@ RSpec.describe RuboCop::Cop::Style::NestedModifier do subject(:cop) { described_class.new } - shared_examples 'avoidable' do |keyword| - it "registers an offense for modifier #{keyword}" do - inspect_source("something #{keyword} a if b") - expect(cop.messages).to eq(['Avoid using nested modifiers.']) - expect(cop.highlights).to eq([keyword]) - end - end - shared_examples 'not correctable' do |keyword| it "does not auto-correct when #{keyword} is the outer modifier" do - source = "something if a #{keyword} b" - corrected = autocorrect_source(source) - expect(corrected).to eq source - expect(cop.offenses.map(&:corrected?)).to eq [false] + expect_offense(<<~RUBY, keyword: keyword) + something if a %{keyword} b + ^^ Avoid using nested modifiers. + RUBY + expect_no_corrections end it "does not auto-correct when #{keyword} is the inner modifier" do - source = "something #{keyword} a if b" - corrected = autocorrect_source(source) - expect(corrected).to eq source - expect(cop.offenses.map(&:corrected?)).to eq [false] + expect_offense(<<~RUBY, keyword: keyword) + something %{keyword} a if b + ^{keyword} Avoid using nested modifiers. + RUBY + expect_no_corrections end end - context 'if' do - it_behaves_like 'avoidable', 'if' - end - - context 'unless' do - it_behaves_like 'avoidable', 'unless' - end - it 'auto-corrects if + if' do - corrected = autocorrect_source('something if a if b') - expect(corrected).to eq 'something if b && a' + expect_offense(<<~RUBY) + something if a if b + ^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something if b && a + RUBY end it 'auto-corrects unless + unless' do - corrected = autocorrect_source('something unless a unless b') - expect(corrected).to eq 'something unless b || a' + expect_offense(<<~RUBY) + something unless a unless b + ^^^^^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something unless b || a + RUBY end it 'auto-corrects if + unless' do - corrected = autocorrect_source('something if a unless b') - expect(corrected).to eq 'something unless b || !a' + expect_offense(<<~RUBY) + something if a unless b + ^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something unless b || !a + RUBY end it 'auto-corrects unless with a comparison operator + if' do - corrected = autocorrect_source('something unless b > 1 if true') - expect(corrected).to eq 'something if true && !(b > 1)' + expect_offense(<<~RUBY) + something unless b > 1 if true + ^^^^^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something if true && !(b > 1) + RUBY end it 'auto-corrects unless + if' do - corrected = autocorrect_source('something unless a if b') - expect(corrected).to eq 'something if b && !a' + expect_offense(<<~RUBY) + something unless a if b + ^^^^^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something if b && !a + RUBY end it 'adds parentheses when needed in auto-correction' do - corrected = autocorrect_source('something if a || b if c || d') - expect(corrected).to eq 'something if (c || d) && (a || b)' + expect_offense(<<~RUBY) + something if a || b if c || d + ^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something if (c || d) && (a || b) + RUBY end it 'adds parentheses to method arguments when needed ' \ 'in auto-correction' do - corrected = autocorrect_source('a unless [1, 2].include? a if a') - expect(corrected).to eq 'a if a && ![1, 2].include?(a)' + expect_offense(<<~RUBY) + a unless [1, 2].include? a if a + ^^^^^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + a if a && ![1, 2].include?(a) + RUBY end it 'does not add redundant parentheses in auto-correction' do - corrected = autocorrect_source('something if a unless c || d') - expect(corrected).to eq 'something unless c || d || !a' + expect_offense(<<~RUBY) + something if a unless c || d + ^^ Avoid using nested modifiers. + RUBY + expect_correction(<<~RUBY) + something unless c || d || !a + RUBY end context 'while' do - it_behaves_like 'avoidable', 'while' it_behaves_like 'not correctable', 'while' end context 'until' do - it_behaves_like 'avoidable', 'until' it_behaves_like 'not correctable', 'until' end @@ -91,5 +115,8 @@ something until a while b unless c if d ^^^^^^ Avoid using nested modifiers. RUBY + expect_correction(<<~RUBY) + something until a while b if d && !c + RUBY end end diff --git a/spec/rubocop/cop/style/nested_parenthesized_calls_spec.rb b/spec/rubocop/cop/style/nested_parenthesized_calls_spec.rb index 3b07096cf92..40be7fd5654 100644 --- a/spec/rubocop/cop/style/nested_parenthesized_calls_spec.rb +++ b/spec/rubocop/cop/style/nested_parenthesized_calls_spec.rb @@ -41,18 +41,15 @@ end context 'when using safe navigation operator' do - let(:source) { 'puts(receiver&.compute something)' } - it 'registers an offense' do expect_offense(<<~RUBY) puts(receiver&.compute something) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add parentheses to nested method call `receiver&.compute something`. RUBY - end - it 'auto-corrects by adding parentheses' do - new_source = autocorrect_source(source) - expect(new_source).to eq('puts(receiver&.compute(something))') + expect_correction(<<~RUBY) + puts(receiver&.compute(something)) + RUBY end end end @@ -102,16 +99,16 @@ end context 'backslash newline in method call' do - let(:source) do - <<~'RUBY' + it 'registers an offense' do + expect_offense(<<~'RUBY') puts(nex \ + ^^^^^ Add parentheses to nested method call [...] 5) RUBY - end - it 'auto-corrects by adding parentheses' do - new_source = autocorrect_source(source.strip) - expect(new_source).to eq('puts(nex(5))') + expect_correction(<<~RUBY) + puts(nex(5)) + RUBY end end end diff --git a/spec/rubocop/cop/style/next_spec.rb b/spec/rubocop/cop/style/next_spec.rb index da3d54407e8..2d94eec9b30 100644 --- a/spec/rubocop/cop/style/next_spec.rb +++ b/spec/rubocop/cop/style/next_spec.rb @@ -7,27 +7,16 @@ let(:opposite) { condition == 'if' ? 'unless' : 'if' } it "registers an offense for #{condition} inside of downto" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) 3.downto(1) do - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) - end - - it "autocorrects #{condition} inside of downto" do - new_source = autocorrect_source(<<~RUBY) - 3.downto(1) do - #{condition} o == 1 - puts o - end - end - RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) 3.downto(1) do next #{opposite} o == 1 puts o @@ -36,27 +25,16 @@ end it "registers an offense for #{condition} inside of each" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].each do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) - end - - it "autocorrects #{condition} inside of each" do - new_source = autocorrect_source(<<~RUBY) - [].each do |o| - #{condition} o == 1 - puts o - end - end - RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) [].each do |o| next #{opposite} o == 1 puts o @@ -65,40 +43,34 @@ end it "registers an offense for #{condition} inside of each_with_object" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].each_with_object({}) do |o, a| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. a[o] = {} end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) - end - - it "registers an offense for #{condition} inside of for" do - inspect_source(<<~RUBY) - for o in 1..3 do - #{condition} o == 1 - puts o - end + expect_correction(<<~RUBY) + [].each_with_object({}) do |o, a| + next #{opposite} o == 1 + a[o] = {} end RUBY - - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) end - it "autocorrects #{condition} inside of for" do - new_source = autocorrect_source(<<~RUBY) + it "registers an offense for #{condition} inside of for" do + expect_offense(<<~RUBY, condition: condition) for o in 1..3 do - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) for o in 1..3 do next #{opposite} o == 1 puts o @@ -107,156 +79,220 @@ end it "registers an offense for #{condition} inside of loop" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) loop do - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + loop do + next #{opposite} o == 1 + puts o + end + RUBY end it "registers an offense for #{condition} inside of map" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) loop do {}.map do |k, v| - #{condition} v == 1 + %{condition} v == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts k end end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} v == 1"]) + expect_correction(<<~RUBY) + loop do + {}.map do |k, v| + next #{opposite} v == 1 + puts k + end + end + RUBY end it "registers an offense for #{condition} inside of times" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) loop do 3.times do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + loop do + 3.times do |o| + next #{opposite} o == 1 + puts o + end + end + RUBY end it "registers an offense for #{condition} inside of collect" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].collect do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. true end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].collect do |o| + next #{opposite} o == 1 + true + end + RUBY end it "registers an offense for #{condition} inside of select" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].select do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. true end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].select do |o| + next #{opposite} o == 1 + true + end + RUBY end it "registers an offense for #{condition} inside of select!" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].select! do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. true end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].select! do |o| + next #{opposite} o == 1 + true + end + RUBY end it "registers an offense for #{condition} inside of reject" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].reject do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. true end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].reject do |o| + next #{opposite} o == 1 + true + end + RUBY end it "registers an offense for #{condition} inside of reject!" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].reject! do |o| - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. true end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].reject! do |o| + next #{opposite} o == 1 + true + end + RUBY end it "registers an offense for #{condition} inside of nested iterators" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) loop do until false - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + loop do + until false + next #{opposite} o == 1 + puts o + end + end + RUBY end it "registers an offense for #{condition} inside of nested iterators" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) loop do while true - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + loop do + while true + next #{opposite} o == 1 + puts o + end + end + RUBY end it 'registers an offense for a condition at the end of an iterator ' \ 'when there is more in the iterator than the condition' do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) [].each do |o| puts o - #{condition} o == 1 + %{condition} o == 1 + ^{condition}^^^^^^^ Use `next` to skip iteration. puts o end end RUBY - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["#{condition} o == 1"]) + expect_correction(<<~RUBY) + [].each do |o| + puts o + next #{opposite} o == 1 + puts o + end + RUBY end it 'allows loops with conditional break' do @@ -318,9 +354,10 @@ end it "reports an offense for #{condition} whose body has 3 lines" do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY, condition: condition) arr.each do |e| - #{condition} something + %{condition} something + ^{condition}^^^^^^^^^^ Use `next` to skip iteration. work work work @@ -328,8 +365,14 @@ end RUBY - expect(cop.offenses.size).to eq(1) - expect(cop.highlights).to eq(["#{condition} something"]) + expect_correction(<<~RUBY) + arr.each do |e| + next #{opposite} something + work + work + work + end + RUBY end context 'EnforcedStyle: skip_modifier_ifs' do @@ -351,24 +394,16 @@ { 'EnforcedStyle' => 'always' } end let(:opposite) { condition == 'if' ? 'unless' : 'if' } - let(:source) do - <<~RUBY + + it "registers an offense for modifier #{condition}" do + expect_offense(<<~RUBY, condition: condition) [].each do |o| puts o #{condition} o == 1 # comment + ^^^^^^^^{condition}^^^^^^^ Use `next` to skip iteration. end RUBY - end - - it "registers an offense for modifier #{condition}" do - inspect_source(source) - - expect(cop.messages).to eq(['Use `next` to skip iteration.']) - expect(cop.highlights).to eq(["puts o #{condition} o == 1"]) - end - it "auto-corrects modifier #{condition}" do - corrected = autocorrect_source(source) - expect(corrected).to eq(<<~RUBY) + expect_correction(<<~RUBY) [].each do |o| next #{opposite} o == 1 puts o # comment @@ -378,9 +413,10 @@ end it 'auto-corrects a misaligned end' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) [1, 2, 3, 4].each do |num| if !opts.nil? + ^^^^^^^^^^^^^ Use `next` to skip iteration. puts num if num != 2 puts 'hello' @@ -390,23 +426,23 @@ end RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) [1, 2, 3, 4].each do |num| next unless !opts.nil? puts num - if num != 2 - puts 'hello' - puts 'world' - end + next unless num != 2 + puts 'hello' + puts 'world' end RUBY end end it 'keeps comments when autocorrecting' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) loop do if test # keep me + ^^^^^^^ Use `next` to skip iteration. # keep me something # keep me # keep me @@ -415,7 +451,7 @@ end RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) loop do next unless test # keep me # keep me @@ -428,14 +464,16 @@ end it 'handles `then` when autocorrecting' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) loop do if test then + ^^^^^^^ Use `next` to skip iteration. something end end RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) loop do next unless test something @@ -444,9 +482,10 @@ end it "doesn't reindent heredoc bodies when autocorrecting" do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) loop do if test + ^^^^^^^ Use `next` to skip iteration. str = <<-BLAH this is a heredoc nice eh? @@ -455,7 +494,8 @@ end end RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) loop do next unless test str = <<-BLAH @@ -468,18 +508,21 @@ end it 'handles nested autocorrections' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) loop do if test + ^^^^^^^ Use `next` to skip iteration. loop do if test + ^^^^^^^ Use `next` to skip iteration. something end end end end RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) loop do next unless test loop do @@ -577,7 +620,7 @@ def foo end RUBY - expect { inspect_source(source) } + expect { expect_no_offenses(source) } .to raise_error('MinBodyLength needs to be a positive integer!') end end diff --git a/spec/rubocop/cop/style/nil_comparison_spec.rb b/spec/rubocop/cop/style/nil_comparison_spec.rb index e7d2ded9005..8d2beea5735 100644 --- a/spec/rubocop/cop/style/nil_comparison_spec.rb +++ b/spec/rubocop/cop/style/nil_comparison_spec.rb @@ -9,6 +9,10 @@ x == nil ^^ Prefer the use of the `nil?` predicate. RUBY + + expect_correction(<<~RUBY) + x.nil? + RUBY end it 'registers an offense for === nil' do @@ -16,16 +20,10 @@ x === nil ^^^ Prefer the use of the `nil?` predicate. RUBY - end - - it 'autocorrects by replacing == nil with .nil?' do - corrected = autocorrect_source('x == nil') - expect(corrected).to eq 'x.nil?' - end - it 'autocorrects by replacing === nil with .nil?' do - corrected = autocorrect_source('x === nil') - expect(corrected).to eq 'x.nil?' + expect_correction(<<~RUBY) + x.nil? + RUBY end end @@ -37,11 +35,10 @@ x.nil? ^^^^ Prefer the use of the `==` comparison. RUBY - end - it 'autocorrects by replacing.nil? with == nil' do - corrected = autocorrect_source('x.nil?') - expect(corrected).to eq 'x == nil' + expect_correction(<<~RUBY) + x == nil + RUBY end end end diff --git a/spec/rubocop/cop/style/non_nil_check_spec.rb b/spec/rubocop/cop/style/non_nil_check_spec.rb index b5f4b6e7176..43b3b136fb9 100644 --- a/spec/rubocop/cop/style/non_nil_check_spec.rb +++ b/spec/rubocop/cop/style/non_nil_check_spec.rb @@ -13,6 +13,10 @@ x != nil ^^ Prefer `!expression.nil?` over `expression != nil`. RUBY + + expect_correction(<<~RUBY) + !x.nil? + RUBY end it 'does not register an offense for != 0' do @@ -61,16 +65,6 @@ def Test.signed_in? RUBY end - it 'autocorrects by changing `!= nil` to `!x.nil?`' do - corrected = autocorrect_source('x != nil') - expect(corrected).to eq '!x.nil?' - end - - it 'does not autocorrect by removing non-nil (!x.nil?) check' do - corrected = autocorrect_source('!x.nil?') - expect(corrected).to eq '!x.nil?' - end - it 'does not blow up when autocorrecting implicit receiver' do corrected = autocorrect_source('!nil?') expect(corrected).to eq '!nil?' @@ -99,6 +93,10 @@ def Test.signed_in? !x.nil? ^^^^^^^ Explicit non-nil checks are usually redundant. RUBY + + expect_correction(<<~RUBY) + x + RUBY end it 'registers an offense for unless x.nil?' do @@ -106,6 +104,10 @@ def Test.signed_in? puts b unless x.nil? ^^^^^^ Explicit non-nil checks are usually redundant. RUBY + + expect_correction(<<~RUBY) + puts b if x + RUBY end it 'does not register an offense for `x.nil?`' do @@ -127,31 +129,37 @@ def Test.signed_in? expect_no_offenses('my_var.nil? ? 1 : 0') end - it 'autocorrects by changing unless x.nil? to if x' do - corrected = autocorrect_source('puts a unless x.nil?') - expect(corrected).to eq 'puts a if x' - end - it 'autocorrects by changing `x != nil` to `x`' do - corrected = autocorrect_source('x != nil') - expect(corrected).to eq 'x' - end + expect_offense(<<~RUBY) + x != nil + ^^ Prefer `!expression.nil?` over `expression != nil`. + RUBY - it 'autocorrects by changing `!x.nil?` to `x`' do - corrected = autocorrect_source('!x.nil?') - expect(corrected).to eq 'x' + expect_correction(<<~RUBY) + x + RUBY end it 'does not blow up when autocorrecting implicit receiver' do - corrected = autocorrect_source('!nil?') - expect(corrected).to eq 'self' + expect_offense(<<~RUBY) + !nil? + ^^^^^ Explicit non-nil checks are usually redundant. + RUBY + expect_correction(<<~RUBY) + self + RUBY end it 'corrects code that would not be modified if ' \ 'IncludeSemanticChanges were false' do - corrected = autocorrect_source('return nil unless (line =~ //) != nil') + expect_offense(<<~RUBY) + return nil unless (line =~ //) != nil + ^^ Prefer `!expression.nil?` over `expression != nil`. + RUBY - expect(corrected).to eq('return nil unless (line =~ //)') + expect_correction(<<~RUBY) + return nil unless (line =~ //) + RUBY end end end diff --git a/spec/rubocop/cop/style/not_spec.rb b/spec/rubocop/cop/style/not_spec.rb index bf6ad28c1a1..524dc3cf311 100644 --- a/spec/rubocop/cop/style/not_spec.rb +++ b/spec/rubocop/cop/style/not_spec.rb @@ -6,6 +6,9 @@ not test ^^^ Use `!` instead of `not`. RUBY + expect_correction(<<~RUBY) + !test + RUBY end it 'does not register an offense for !' do @@ -13,42 +16,72 @@ end it 'auto-corrects "not" with !' do - new_source = autocorrect_source('x = 10 if not y') - expect(new_source).to eq('x = 10 if !y') + expect_offense(<<~RUBY) + x = 10 if not y + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + x = 10 if !y + RUBY end it 'auto-corrects "not" followed by parens with !' do - new_source = autocorrect_source('not(test)') - expect(new_source).to eq('!(test)') + expect_offense(<<~RUBY) + not(test) + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + !(test) + RUBY end it 'uses the reverse operator when `not` is applied to a comparison' do - src = 'not x < y' - new_source = autocorrect_source(src) - expect(new_source).to eq('x >= y') + expect_offense(<<~RUBY) + not x < y + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + x >= y + RUBY end it 'parenthesizes when `not` would change the meaning of a binary exp' do - src = 'not a >> b' - new_source = autocorrect_source(src) - expect(new_source).to eq('!(a >> b)') + expect_offense(<<~RUBY) + not a >> b + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + !(a >> b) + RUBY end it 'parenthesizes when `not` is applied to a ternary op' do - src = 'not a ? b : c' - new_source = autocorrect_source(src) - expect(new_source).to eq('!(a ? b : c)') + expect_offense(<<~RUBY) + not a ? b : c + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + !(a ? b : c) + RUBY end it 'parenthesizes when `not` is applied to and' do - src = 'not a && b' - new_source = autocorrect_source(src) - expect(new_source).to eq('!(a && b)') + expect_offense(<<~RUBY) + not a && b + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + !(a && b) + RUBY end it 'parenthesizes when `not` is applied to or' do - src = 'not a || b' - new_source = autocorrect_source(src) - expect(new_source).to eq('!(a || b)') + expect_offense(<<~RUBY) + not a || b + ^^^ Use `!` instead of `not`. + RUBY + expect_correction(<<~RUBY) + !(a || b) + RUBY end end diff --git a/spec/rubocop/cop/style/numeric_literal_prefix_spec.rb b/spec/rubocop/cop/style/numeric_literal_prefix_spec.rb index 4138e2014d1..b0eaf6c7bd6 100644 --- a/spec/rubocop/cop/style/numeric_literal_prefix_spec.rb +++ b/spec/rubocop/cop/style/numeric_literal_prefix_spec.rb @@ -16,6 +16,11 @@ b(0O1234) ^^^^^^ Use 0o for octal literals. RUBY + + expect_correction(<<~RUBY) + a = 0o1234 + b(0o1234) + RUBY end it 'does not register offense for lowercase prefix' do @@ -24,16 +29,6 @@ b = 0o567 RUBY end - - it 'autocorrects an octal literal starting with 0' do - corrected = autocorrect_source('a = 01234') - expect(corrected).to eq('a = 0o1234') - end - - it 'autocorrects an octal literal starting with 0O' do - corrected = autocorrect_source('b(0O1234, a)') - expect(corrected).to eq('b(0o1234, a)') - end end context 'when config is zero_only' do @@ -50,27 +45,15 @@ b(0o1234) ^^^^^^ Use 0 for octal literals. RUBY - end - - it 'does not register offense for prefix `0`' do - expect_no_offenses('b = 0567') - end - - it 'autocorrects an octal literal starting with 0O or 0o' do - corrected = autocorrect_source(<<~RUBY) - a = 0O1234 - b(0o1234) - RUBY - expect(corrected).to eq <<~RUBY + expect_correction(<<~RUBY) a = 01234 b(01234) RUBY end - it 'does not autocorrect an octal literal starting with 0' do - corrected = autocorrect_source('b(01234, a)') - expect(corrected).to eq 'b(01234, a)' + it 'does not register offense for prefix `0`' do + expect_no_offenses('b = 0567') end end end @@ -83,16 +66,16 @@ b(0XABC) ^^^^^ Use 0x for hexadecimal literals. RUBY + + expect_correction(<<~RUBY) + a = 0x1AC + b(0xABC) + RUBY end it 'does not register offense for lowercase prefix' do expect_no_offenses('a = 0x101') end - - it 'autocorrects literals with uppercase prefix' do - corrected = autocorrect_source('a = 0XAB') - expect(corrected).to eq 'a = 0xAB' - end end context 'binary literals' do @@ -103,16 +86,16 @@ b(0B111) ^^^^^ Use 0b for binary literals. RUBY + + expect_correction(<<~RUBY) + a = 0b10101 + b(0b111) + RUBY end it 'does not register offense for lowercase prefix' do expect_no_offenses('a = 0b101') end - - it 'autocorrects literals with uppercase prefix' do - corrected = autocorrect_source('a = 0B1010') - expect(corrected).to eq 'a = 0b1010' - end end context 'decimal literals' do @@ -120,33 +103,18 @@ expect_offense(<<~RUBY) a = 0d1234 ^^^^^^ Do not use prefixes for decimal literals. - b(0D1234) + b(0D1990) ^^^^^^ Do not use prefixes for decimal literals. RUBY - end - - it 'does not register offense for no prefix' do - expect_no_offenses('a = 101') - end - it 'autocorrects literals with prefix' do - corrected = autocorrect_source(<<~RUBY) - a = 0d1234 - b(0D1990) - RUBY - expect(corrected).to eq(<<~RUBY) + expect_correction(<<~RUBY) a = 1234 b(1990) RUBY end - it 'does not autocorrect literals with no prefix' do - source = <<~RUBY - a = 1234 - b(1990) - RUBY - corrected = autocorrect_source(source) - expect(corrected).to eq(source) + it 'does not register offense for no prefix' do + expect_no_offenses('a = 101') end end end diff --git a/spec/rubocop/cop/style/numeric_literals_spec.rb b/spec/rubocop/cop/style/numeric_literals_spec.rb index b1bee7e236c..c20258ec123 100644 --- a/spec/rubocop/cop/style/numeric_literals_spec.rb +++ b/spec/rubocop/cop/style/numeric_literals_spec.rb @@ -8,6 +8,10 @@ a = 12345 ^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. RUBY + + expect_correction(<<~RUBY) + a = 12_345 + RUBY end it 'registers an offense for a float with a long undelimited integer part' do @@ -15,6 +19,10 @@ a = 123456.789 ^^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. RUBY + + expect_correction(<<~RUBY) + a = 123_456.789 + RUBY end it 'accepts integers with less than three places at the end' do @@ -25,12 +33,18 @@ end it 'registers an offense for an integer with misplaced underscore' do - inspect_source(<<~RUBY) + expect_offense(<<~RUBY) a = 123_456_78_90_00 + ^^^^^^^^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. b = 1_8192 + ^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. RUBY - expect(cop.offenses.size).to eq(2) expect(cop.config_to_allow_offenses).to eq('Enabled' => false) + + expect_correction(<<~RUBY) + a = 123_456_789_000 + b = 18_192 + RUBY end it 'accepts long numbers with underscore' do @@ -71,51 +85,69 @@ d = 12345e3 ^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. RUBY - end - - it 'autocorrects a long integer offense' do - corrected = autocorrect_source('a = 123456') - expect(corrected).to eq 'a = 123_456' - end - it 'autocorrects an integer with misplaced underscore' do - corrected = autocorrect_source('a = 123_456_78_90_00') - expect(corrected).to eq 'a = 123_456_789_000' + expect_correction(<<~RUBY) + a = 10e10 + b = 3e12345 + c = 12.345e3 + d = 12_345e3 + RUBY end it 'autocorrects negative numbers' do - corrected = autocorrect_source('a = -123456') - expect(corrected).to eq 'a = -123_456' - end + expect_offense(<<~RUBY) + a = -123456 + ^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY - it 'autocorrects floating-point numbers' do - corrected = autocorrect_source('a = 123456.78') - expect(corrected).to eq 'a = 123_456.78' + expect_correction(<<~RUBY) + a = -123_456 + RUBY end it 'autocorrects negative floating-point numbers' do - corrected = autocorrect_source('a = -123456.78') - expect(corrected).to eq 'a = -123_456.78' + expect_offense(<<~RUBY) + a = -123456.78 + ^^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY + + expect_correction(<<~RUBY) + a = -123_456.78 + RUBY end it 'autocorrects numbers with spaces between leading minus and numbers' do - corrected = autocorrect_source("a = -\n 12345") - expect(corrected).to eq 'a = -12_345' - end + expect_offense(<<~RUBY) + a = - + ^ Use underscores(_) as thousands separator and separate every 3 digits with them. + 12345 + RUBY - it 'autocorrects numeric literal with exponent' do - corrected = autocorrect_source('a = 12345e3') - expect(corrected).to eq 'a = 12_345e3' + expect_correction(<<~RUBY) + a = -12_345 + RUBY end it 'autocorrects numeric literal with exponent and dot' do - corrected = autocorrect_source('a = 12345.6e3') - expect(corrected).to eq 'a = 12_345.6e3' + expect_offense(<<~RUBY) + a = 12345.6e3 + ^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY + + expect_correction(<<~RUBY) + a = 12_345.6e3 + RUBY end it 'autocorrects numeric literal with exponent (large E) and dot' do - corrected = autocorrect_source('a = 12345.6E3') - expect(corrected).to eq 'a = 12_345.6E3' + expect_offense(<<~RUBY) + a = 12345.6E3 + ^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY + + expect_correction(<<~RUBY) + a = 12_345.6E3 + RUBY end context 'strict' do @@ -131,6 +163,10 @@ a = 123_456_78_90_00 ^^^^^^^^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. RUBY + + expect_correction(<<~RUBY) + a = 123_456_789_000 + RUBY end end end diff --git a/spec/rubocop/cop/style/numeric_predicate_spec.rb b/spec/rubocop/cop/style/numeric_predicate_spec.rb index 0943d945129..cb141694571 100644 --- a/spec/rubocop/cop/style/numeric_predicate_spec.rb +++ b/spec/rubocop/cop/style/numeric_predicate_spec.rb @@ -1,153 +1,176 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Style::NumericPredicate, :config do - before do - inspect_source(source) - end - - shared_examples( - 'code with offense' - ) do |code, options| - context "when checking #{code}" do - let(:source) { code } - let(:use) { options[:use] || options[:expected] } - let(:instead_of) { options[:instead_of] || code } - - let(:message) { "Use `#{use}` instead of `#{instead_of}`." } - - it 'registers an offense' do - expect(cop.offenses.size).to eq(1) - expect(cop.messages).to eq([message]) - end - - if (expected = options[:expected]) - it 'auto-corrects' do - expect(autocorrect_source(code)).to eq(expected) - end - else - it 'does not auto-correct' do - expect(autocorrect_source(code)).to eq(code) - end - end - end - end - - shared_examples 'code without offense' do |code| - let(:source) { code } - - it 'does not register an offense' do - expect(cop.offenses.empty?).to be(true) - end - end - context 'when configured to enforce numeric predicate methods' do let(:cop_config) do { 'EnforcedStyle' => 'predicate', 'AutoCorrect' => true } end context 'when checking if a number is zero' do - it_behaves_like 'code with offense', - 'number == 0', - expected: 'number.zero?' - - it_behaves_like 'code with offense', - '0 == number', - expected: 'number.zero?' - - context 'with a complex expression' do - it_behaves_like 'code with offense', - 'foo - 1 == 0', - expected: '(foo - 1).zero?' - - it_behaves_like 'code with offense', - '0 == foo - 1', - expected: '(foo - 1).zero?' + it 'registers an offense' do + expect_offense(<<~RUBY) + number == 0 + ^^^^^^^^^^^ Use `number.zero?` instead of `number == 0`. + 0 == number + ^^^^^^^^^^^ Use `number.zero?` instead of `0 == number`. + RUBY + expect_correction(<<~RUBY) + number.zero? + number.zero? + RUBY end - context 'when comparing against a global variable' do - it_behaves_like 'code without offense', - '$CHILD_STATUS == 0' + it 'registers an offense with a complex expression' do + expect_offense(<<~RUBY) + foo - 1 == 0 + ^^^^^^^^^^^^ Use `(foo - 1).zero?` instead of `foo - 1 == 0`. + 0 == foo - 1 + ^^^^^^^^^^^^ Use `(foo - 1).zero?` instead of `0 == foo - 1`. + RUBY + expect_correction(<<~RUBY) + (foo - 1).zero? + (foo - 1).zero? + RUBY + end - it_behaves_like 'code without offense', - '0 == $CHILD_STATUS' + it 'allows comparing against a global variable' do + expect_no_offenses('$CHILD_STATUS == 0') + expect_no_offenses('0 == $CHILD_STATUS') end context 'when comparing against a method argument variable' do - it_behaves_like 'code with offense', - 'def m(foo); foo == 0; end', - expected: 'def m(foo); foo.zero?; end', - use: 'foo.zero?', - instead_of: 'foo == 0' - - it_behaves_like 'code with offense', - 'def m(foo); foo - 1 == 0; end', - expected: 'def m(foo); (foo - 1).zero?; end', - use: '(foo - 1).zero?', - instead_of: 'foo - 1 == 0' + it 'registers an offense' do + expect_offense(<<~RUBY) + def m(foo) + foo == 0 + ^^^^^^^^ Use `foo.zero?` instead of `foo == 0`. + end + RUBY + expect_correction(<<~RUBY) + def m(foo) + foo.zero? + end + RUBY + end + + it 'registers an offense with complex expression' do + expect_offense(<<~RUBY) + def m(foo) + foo - 1 == 0 + ^^^^^^^^^^^^ Use `(foo - 1).zero?` instead of `foo - 1 == 0`. + end + RUBY + expect_correction(<<~RUBY) + def m(foo) + (foo - 1).zero? + end + RUBY + end end end context 'with checking if a number is not zero' do - it_behaves_like 'code without offense', - 'number != 0' - - it_behaves_like 'code without offense', - '0 != number' - - context 'with a complex expression' do - it_behaves_like 'code without offense', - 'foo - 1 != 0' - - it_behaves_like 'code without offense', - '0 != foo - 1' + it 'allows comparing against a variable' do + expect_no_offenses('number != 0') + expect_no_offenses('0 != number') end - context 'when comparing against a global variable' do - it_behaves_like 'code without offense', - '$CHILD_STATUS != 0' + it 'allows comparing against a complex expression' do + expect_no_offenses('foo - 1 != 0') + expect_no_offenses('0 != foo - 1') + end - it_behaves_like 'code without offense', - '0 != $CHILD_STATUS' + it 'allows comparing against a global variable' do + expect_no_offenses('$CHILD_STATUS != 0') + expect_no_offenses('0 != $CHILD_STATUS') end end context 'when checking if a number is positive' do - it_behaves_like 'code with offense', - 'number > 0', - expected: 'number.positive?' + it 'registers an offense' do + expect_offense(<<~RUBY) + number > 0 + ^^^^^^^^^^ Use `number.positive?` instead of `number > 0`. + RUBY + expect_correction(<<~RUBY) + number.positive? + RUBY + end - it_behaves_like 'code with offense', - '0 < number', - expected: 'number.positive?' + it 'registers an offense in yoda condition' do + expect_offense(<<~RUBY) + 0 < number + ^^^^^^^^^^ Use `number.positive?` instead of `0 < number`. + RUBY + expect_correction(<<~RUBY) + number.positive? + RUBY + end context 'with a complex expression' do - it_behaves_like 'code with offense', - 'foo - 1 > 0', - expected: '(foo - 1).positive?' + it 'registers an offense' do + expect_offense(<<~RUBY) + foo - 1 > 0 + ^^^^^^^^^^^ Use `(foo - 1).positive?` instead of `foo - 1 > 0`. + RUBY + expect_correction(<<~RUBY) + (foo - 1).positive? + RUBY + end - it_behaves_like 'code with offense', - '0 < foo - 1', - expected: '(foo - 1).positive?' + it 'registers an offense in yoda condition' do + expect_offense(<<~RUBY) + 0 < foo - 1 + ^^^^^^^^^^^ Use `(foo - 1).positive?` instead of `0 < foo - 1`. + RUBY + expect_correction(<<~RUBY) + (foo - 1).positive? + RUBY + end end end context 'when checking if a number is negative' do - it_behaves_like 'code with offense', - 'number < 0', - expected: 'number.negative?' + it 'registers an offense' do + expect_offense(<<~RUBY) + number < 0 + ^^^^^^^^^^ Use `number.negative?` instead of `number < 0`. + RUBY + expect_correction(<<~RUBY) + number.negative? + RUBY + end - it_behaves_like 'code with offense', - '0 > number', - expected: 'number.negative?' + it 'registers an offense in yoda condition' do + expect_offense(<<~RUBY) + 0 > number + ^^^^^^^^^^ Use `number.negative?` instead of `0 > number`. + RUBY + expect_correction(<<~RUBY) + number.negative? + RUBY + end context 'with a complex expression' do - it_behaves_like 'code with offense', - 'foo - 1 < 0', - expected: '(foo - 1).negative?' + it 'registers an offense' do + expect_offense(<<~RUBY) + foo - 1 < 0 + ^^^^^^^^^^^ Use `(foo - 1).negative?` instead of `foo - 1 < 0`. + RUBY + expect_correction(<<~RUBY) + (foo - 1).negative? + RUBY + end - it_behaves_like 'code with offense', - '0 > foo - 1', - expected: '(foo - 1).negative?' + it 'registers an offense in yoda condition' do + expect_offense(<<~RUBY) + 0 > foo - 1 + ^^^^^^^^^^^ Use `(foo - 1).negative?` instead of `0 > foo - 1`. + RUBY + expect_correction(<<~RUBY) + (foo - 1).negative? + RUBY + end end end end @@ -157,27 +180,38 @@ { 'EnforcedStyle' => 'comparison', 'AutoCorrect' => true } end - context 'when checking if a number is zero' do - it_behaves_like 'code with offense', - 'number.zero?', - expected: 'number == 0' + it 'registers an offense for checking if a number is zero' do + expect_offense(<<~RUBY) + number.zero? + ^^^^^^^^^^^^ Use `number == 0` instead of `number.zero?`. + RUBY + expect_correction(<<~RUBY) + number == 0 + RUBY end - context 'with checking if a number is not zero' do - it_behaves_like 'code without offense', - 'number.nonzero?' + it 'allows checking if a number is not zero' do + expect_no_offenses('number.nonzero?') end - context 'when checking if a number is positive' do - it_behaves_like 'code with offense', - 'number.positive?', - expected: 'number > 0' + it 'registers an offense for checking if a number is positive' do + expect_offense(<<~RUBY) + number.positive? + ^^^^^^^^^^^^^^^^ Use `number > 0` instead of `number.positive?`. + RUBY + expect_correction(<<~RUBY) + number > 0 + RUBY end - context 'when checking if a number is negative' do - it_behaves_like 'code with offense', - 'number.negative?', - expected: 'number < 0' + it 'registers an offense for checking if a number is negative' do + expect_offense(<<~RUBY) + number.negative? + ^^^^^^^^^^^^^^^^ Use `number < 0` instead of `number.negative?`. + RUBY + expect_correction(<<~RUBY) + number < 0 + RUBY end end @@ -199,8 +233,8 @@ } end - context 'when checking if a number is zero' do - it_behaves_like 'code without offense', <<~RUBY + it 'allows checking if a number is zero' do + expect_no_offenses(<<~RUBY) if number == 0 puts 'hello' end @@ -216,8 +250,8 @@ } end - context 'when checking if a number is zero' do - it_behaves_like 'code without offense', <<~RUBY + it 'allows checking if a number is zero' do + expect_no_offenses(<<~RUBY) if number.zero? puts 'hello' end @@ -228,60 +262,68 @@ context 'in argument' do context 'ignored method' do - context 'when checking if a number is positive' do - it_behaves_like 'code without offense', 'where(Sequel[:number] > 0)' + it 'allows checking if a number is positive' do + expect_no_offenses('where(Sequel[:number] > 0)') end - context 'when checking if a number is negative' do - it_behaves_like 'code without offense', 'where(Sequel[:number] < 0)' + it 'allows checking if a number is negative' do + expect_no_offenses('where(Sequel[:number] < 0)') end end context 'not ignored method' do - context 'when checking if a number is positive' do - it_behaves_like 'code with offense', - 'exclude(number > 0)', - expected: 'exclude(number.positive?)', - use: 'number.positive?', - instead_of: 'number > 0' + it 'registers an offense for checking if a number is positive' do + expect_offense(<<~RUBY) + exclude(number > 0) + ^^^^^^^^^^ Use `number.positive?` instead of `number > 0`. + RUBY + expect_correction(<<~RUBY) + exclude(number.positive?) + RUBY end - context 'when checking if a number is negative' do - it_behaves_like 'code with offense', - 'exclude(number < 0)', - expected: 'exclude(number.negative?)', - use: 'number.negative?', - instead_of: 'number < 0' + it 'registers an offense for checking if a number is negative' do + expect_offense(<<~RUBY) + exclude(number < 0) + ^^^^^^^^^^ Use `number.negative?` instead of `number < 0`. + RUBY + expect_correction(<<~RUBY) + exclude(number.negative?) + RUBY end end end context 'in block' do context 'ignored method' do - context 'when checking if a number is positive' do - it_behaves_like 'code without offense', 'where { table[number] > 0 }' + it 'allows checking if a number is positive' do + expect_no_offenses('where { table[number] > 0 }') end - context 'when checking if a number is negative' do - it_behaves_like 'code without offense', 'where { table[number] < 0 }' + it 'allows checking if a number is negative' do + expect_no_offenses('where { table[number] < 0 }') end end context 'not ignored method' do - context 'when checking if a number is positive' do - it_behaves_like 'code with offense', - 'exclude { number > 0 }', - expected: 'exclude { number.positive? }', - use: 'number.positive?', - instead_of: 'number > 0' + it 'registers an offense for checking if a number is positive' do + expect_offense(<<~RUBY) + exclude { number > 0 } + ^^^^^^^^^^ Use `number.positive?` instead of `number > 0`. + RUBY + expect_correction(<<~RUBY) + exclude { number.positive? } + RUBY end - context 'when checking if a number is negative' do - it_behaves_like 'code with offense', - 'exclude { number < 0 }', - expected: 'exclude { number.negative? }', - use: 'number.negative?', - instead_of: 'number < 0' + it 'registers an offense for checking if a number is negative' do + expect_offense(<<~RUBY) + exclude { number < 0 } + ^^^^^^^^^^ Use `number.negative?` instead of `number < 0`. + RUBY + expect_correction(<<~RUBY) + exclude { number.negative? } + RUBY end end end diff --git a/spec/rubocop/cop/style/one_line_conditional_spec.rb b/spec/rubocop/cop/style/one_line_conditional_spec.rb index 73e8daa19eb..58f2df65018 100644 --- a/spec/rubocop/cop/style/one_line_conditional_spec.rb +++ b/spec/rubocop/cop/style/one_line_conditional_spec.rb @@ -3,86 +3,81 @@ RSpec.describe RuboCop::Cop::Style::OneLineConditional do subject(:cop) { described_class.new } - shared_examples 'offense' do |condition| + context 'one line if/then/else/end' do it 'registers an offense' do - inspect_source(source) - expect(cop.messages) - .to eq(['Favor the ternary operator (`?:`)' \ - " over `#{condition}/then/else/end` constructs."]) - end - end - - shared_examples 'no offense' do - it 'does not register an offense' do - expect_no_offenses(source) + expect_offense(<<~RUBY) + if cond then run else dont end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + expect_correction(<<~RUBY) + cond ? run : dont + RUBY end - end - - shared_examples 'autocorrect' do |correct_code| - it 'auto-corrects' do - corrected = autocorrect_source(source) - expect(corrected).to eq(correct_code) - end - end - context 'one line if/then/else/end' do - let(:source) { 'if cond then run else dont end' } - - include_examples 'offense', 'if' - include_examples 'autocorrect', 'cond ? run : dont' - - context 'empty else' do - let(:source) { 'if cond then run else end' } - - include_examples 'no offense' + it 'allows empty else' do + expect_no_offenses('if cond then run else end') end end context 'one line if/then/else/end when `then` branch has no body' do - let(:source) { 'if cond then else dont end' } - - include_examples 'offense', 'if' - include_examples 'autocorrect', 'cond ? nil : dont' + it 'registers an offense' do + expect_offense(<<~RUBY) + if cond then else dont end + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + expect_correction(<<~RUBY) + cond ? nil : dont + RUBY + end end - context 'one line if/then/end' do - let(:source) { 'if cond then run end' } - - include_examples 'no offense' + it 'allows one line if/then/end' do + expect_no_offenses('if cond then run end') end context 'one line unless/then/else/end' do - let(:source) { 'unless cond then run else dont end' } - - include_examples 'offense', 'unless' - include_examples 'autocorrect', 'cond ? dont : run' - - context 'empty else' do - let(:source) { 'unless cond then run else end' } + it 'registers an offense' do + expect_offense(<<~RUBY) + unless cond then run else dont end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `unless/then/else/end` constructs. + RUBY + expect_correction(<<~RUBY) + cond ? dont : run + RUBY + end - include_examples 'no offense' + it 'allows empty else' do + expect_no_offenses('unless cond then run else end') end end - context 'one line unless/then/end' do - let(:source) { 'unless cond then run end' } - - include_examples 'no offense' + it 'allows one line unless/then/end' do + expect_no_offenses('unless cond then run end') end %w[| ^ & <=> == === =~ > >= < <= << >> + - * / % ** ~ ! != !~ && ||].each do |operator| it 'parenthesizes the expression if it is preceded by an operator' do - corrected = - autocorrect_source("a #{operator} if cond then run else dont end") - expect(corrected).to eq("a #{operator} (cond ? run : dont)") + expect_offense(<<~RUBY, operator: operator) + a %{operator} if cond then run else dont end + _{operator} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + expect_correction(<<~RUBY) + a #{operator} (cond ? run : dont) + RUBY end end shared_examples 'changed precedence' do |expr| it "adds parentheses around `#{expr}`" do - corrected = autocorrect_source("if #{expr} then #{expr} else #{expr} end") - expect(corrected).to eq("(#{expr}) ? (#{expr}) : (#{expr})") + expect_offense(<<~RUBY, expr: expr) + if %{expr} then %{expr} else %{expr} end + ^^^^{expr}^^^^^^^{expr}^^^^^^^{expr}^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + + expect_correction(<<~RUBY) + (#{expr}) ? (#{expr}) : (#{expr}) + RUBY end end @@ -98,15 +93,26 @@ it 'does not parenthesize expressions when they do not contain method ' \ 'calls with unparenthesized arguments' do - corrected = - autocorrect_source('if a(0) then puts(1) else yield(2) end') - expect(corrected).to eq('a(0) ? puts(1) : yield(2)') + expect_offense(<<~RUBY) + if a(0) then puts(1) else yield(2) end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + + expect_correction(<<~RUBY) + a(0) ? puts(1) : yield(2) + RUBY end it 'does not parenthesize expressions when they contain unparenthesized ' \ 'operator method calls' do - corrected = autocorrect_source('if 0 + 0 then 1 + 1 else 2 + 2 end') - expect(corrected).to eq('0 + 0 ? 1 + 1 : 2 + 2') + expect_offense(<<~RUBY) + if 0 + 0 then 1 + 1 else 2 + 2 end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Favor the ternary operator (`?:`) over `if/then/else/end` constructs. + RUBY + + expect_correction(<<~RUBY) + 0 + 0 ? 1 + 1 : 2 + 2 + RUBY end it 'does not break when one of the branches contains a retry keyword' do diff --git a/spec/rubocop/cop/style/or_assignment_spec.rb b/spec/rubocop/cop/style/or_assignment_spec.rb index 7ec9df90fcc..9c3618b8047 100644 --- a/spec/rubocop/cop/style/or_assignment_spec.rb +++ b/spec/rubocop/cop/style/or_assignment_spec.rb @@ -11,6 +11,10 @@ foo = foo ? foo : 'default' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + foo ||= 'default' + RUBY end it 'registers an offense with instance variables' do @@ -18,6 +22,10 @@ @foo = @foo ? @foo : 'default' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + @foo ||= 'default' + RUBY end it 'registers an offense with class variables' do @@ -25,6 +33,10 @@ @@foo = @@foo ? @@foo : 'default' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + @@foo ||= 'default' + RUBY end it 'registers an offense with global variables' do @@ -32,22 +44,10 @@ $foo = $foo ? $foo : 'default' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY - end - - it 'autocorrects normal variables to `var ||= something`' do - expect(autocorrect_source('x = x ? x : 3')).to eq('x ||= 3') - end - it 'autocorrects instance variables to `var ||= something`' do - expect(autocorrect_source('@x = @x ? @x : 3')).to eq('@x ||= 3') - end - - it 'autocorrects class variables to `var ||= something`' do - expect(autocorrect_source('@@x = @@x ? @@x : 3')).to eq('@@x ||= 3') - end - - it 'autocorrects global variables to `var ||= something`' do - expect(autocorrect_source('$x = $x ? $x : 3')).to eq('$x ||= 3') + expect_correction(<<~RUBY) + $foo ||= 'default' + RUBY end it 'does not register an offense if any of the variables are different' do @@ -66,6 +66,10 @@ 'default' end RUBY + + expect_correction(<<~RUBY) + foo ||= 'default' + RUBY end it 'registers an offense with instance variables' do @@ -77,6 +81,10 @@ 'default' end RUBY + + expect_correction(<<~RUBY) + @foo ||= 'default' + RUBY end it 'registers an offense with class variables' do @@ -88,6 +96,10 @@ 'default' end RUBY + + expect_correction(<<~RUBY) + @@foo ||= 'default' + RUBY end it 'registers an offense with global variables' do @@ -99,45 +111,9 @@ 'default' end RUBY - end - - it 'autocorrects normal variables to `var ||= something`' do - expect(autocorrect_source(<<~RUBY)).to eq("x ||= 3\n") - x = if x - x - else - 3 - end - RUBY - end - - it 'autocorrects instance variables to `var ||= something`' do - expect(autocorrect_source(<<~RUBY)).to eq("@x ||= 3\n") - @x = if @x - @x - else - 3 - end - RUBY - end - it 'autocorrects class variables to `var ||= something`' do - expect(autocorrect_source(<<~RUBY)).to eq("@@x ||= 3\n") - @@x = if @@x - @@x - else - 3 - end - RUBY - end - - it 'autocorrects global variables to `var ||= something`' do - expect(autocorrect_source(<<~RUBY)).to eq("$x ||= 3\n") - $x = if $x - $x - else - 3 - end + expect_correction(<<~RUBY) + $foo ||= 'default' RUBY end @@ -165,6 +141,10 @@ foo = 'default' unless foo ^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + foo ||= 'default' + RUBY end it 'registers an offense for instance variables' do @@ -172,6 +152,10 @@ @foo = 'default' unless @foo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + @foo ||= 'default' + RUBY end it 'registers an offense for class variables' do @@ -179,6 +163,10 @@ @@foo = 'default' unless @@foo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY + + expect_correction(<<~RUBY) + @@foo ||= 'default' + RUBY end it 'registers an offense for global variables' do @@ -186,22 +174,10 @@ $foo = 'default' unless $foo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the double pipe equals operator `||=` instead. RUBY - end - - it 'autocorrects normal variables to `var ||= something`' do - expect(autocorrect_source('x = 3 unless x')).to eq('x ||= 3') - end - it 'autocorrects instance variables to `var ||= something`' do - expect(autocorrect_source('@x = 3 unless @x')).to eq('@x ||= 3') - end - - it 'autocorrects class variables to `var ||= something`' do - expect(autocorrect_source('@@x = 3 unless @@x')).to eq('@@x ||= 3') - end - - it 'autocorrects global variables to `var ||= something`' do - expect(autocorrect_source('$x = 3 unless $x')).to eq('$x ||= 3') + expect_correction(<<~RUBY) + $foo ||= 'default' + RUBY end it 'does not register an offense if any of the variables are different' do @@ -223,6 +199,11 @@ foo = 'default' end RUBY + + expect_correction(<<~RUBY) + foo = nil + foo ||= 'default' + RUBY end it 'registers an offense for instance variables' do @@ -233,6 +214,11 @@ @foo = 'default' end RUBY + + expect_correction(<<~RUBY) + @foo = nil + @foo ||= 'default' + RUBY end it 'registers an offense for class variables' do @@ -243,6 +229,11 @@ @@foo = 'default' end RUBY + + expect_correction(<<~RUBY) + @@foo = nil + @@foo ||= 'default' + RUBY end it 'registers an offense for global variables' do @@ -253,46 +244,11 @@ $foo = 'default' end RUBY - end - - it 'autocorrects normal variables to `var ||= something`' do - new_source_normal = autocorrect_source(<<~RUBY) - foo = nil - unless foo - foo = 3 - end - RUBY - expect(new_source_normal).to eq("foo = nil\nfoo ||= 3\n") - end - it 'autocorrects instance variables to `var ||= something`' do - new_source_instance = autocorrect_source(<<~RUBY) - @foo = nil - unless @foo - @foo = 3 - end - RUBY - expect(new_source_instance).to eq("@foo = nil\n@foo ||= 3\n") - end - - it 'autocorrects class variables to `var ||= something`' do - new_source_class = autocorrect_source(<<~RUBY) - @@foo = nil - unless @@foo - @@foo = 3 - end - RUBY - expect(new_source_class).to eq("@@foo = nil\n@@foo ||= 3\n") - end - - it 'autocorrects global variables to `var ||= something`' do - new_source_global = autocorrect_source(<<~RUBY) + expect_correction(<<~RUBY) $foo = nil - unless $foo - $foo = 3 - end + $foo ||= 'default' RUBY - expect(new_source_global).to eq("$foo = nil\n$foo ||= 3\n") end it 'does not register an offense if any of the variables are different' do diff --git a/spec/rubocop/cop/style/parallel_assignment_spec.rb b/spec/rubocop/cop/style/parallel_assignment_spec.rb index 8196c99e4ba..f8ed540924e 100644 --- a/spec/rubocop/cop/style/parallel_assignment_spec.rb +++ b/spec/rubocop/cop/style/parallel_assignment_spec.rb @@ -5,47 +5,195 @@ RuboCop::Config.new('Layout/IndentationWidth' => { 'Width' => 2 }) end - shared_examples('offenses') do |source| - it "registers an offense for: #{source.gsub(/\s*\n\s*/, '; ')}" do - inspect_source(source) + it 'registers an offense when the right side has mulitple arrays' do + expect_offense(<<~RUBY) + a, b, c = [1, 2], [3, 4], [5, 6] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(cop.messages).to eq(['Do not use parallel assignment.']) - end + expect_correction(<<~RUBY) + a = [1, 2] + b = [3, 4] + c = [5, 6] + RUBY end - it_behaves_like('offenses', 'a, b, c = 1, 2, 3') - it_behaves_like('offenses', 'a, b, c = [1, 2, 3]') - it_behaves_like('offenses', 'a, b, c = [1, 2], [3, 4], [5, 6]') - it_behaves_like('offenses', 'a, b, c = {a: 1}, {b: 2}, {c: 3}') - it_behaves_like('offenses', 'a, b, c = CONSTANT1, CONSTANT2, CONSTANT3') - it_behaves_like('offenses', 'a, b, c = [1, 2], {a: 1}, CONSTANT3') - it_behaves_like('offenses', 'a, b = foo(), bar()') - it_behaves_like('offenses', 'a, b = foo { |a| puts a }, bar()') - it_behaves_like('offenses', 'CONSTANT1, CONSTANT2 = CONSTANT3, CONSTANT4') - it_behaves_like('offenses', 'a, b = 1, 2 if something') - it_behaves_like('offenses', 'a, b = 1, 2 unless something') - it_behaves_like('offenses', 'a, b = 1, 2 while something') - it_behaves_like('offenses', 'a, b = 1, 2 until something') - it_behaves_like('offenses', "a, b = 1, 2 rescue 'Error'") - it_behaves_like('offenses', 'a, b = 1, a') - it_behaves_like('offenses', 'a, b = a, b') - it_behaves_like('offenses', - 'a, b = foo.map { |e| e.id }, bar.map { |e| e.id }') - it_behaves_like('offenses', <<~RUBY) - array = [1, 2, 3] - a, b, c, = 8, 9, array - RUBY - it_behaves_like('offenses', <<~RUBY) - if true - a, b = 1, 2 - end - RUBY - it_behaves_like('offenses', 'a, b = Float::INFINITY, Float::INFINITY') - it_behaves_like('offenses', 'Float::INFINITY, Float::INFINITY = 1, 2') - it_behaves_like('offenses', 'a[0], a[1] = a[1], a[2]') - it_behaves_like('offenses', 'obj.attr1, obj.attr2 = obj.attr3, obj.attr1') - it_behaves_like('offenses', 'obj.attr1, ary[0] = ary[1], obj.attr1') - it_behaves_like('offenses', 'a[0], a[1] = a[1], b[0]') + it 'registers an offense when the right side has multiple hashes' do + expect_offense(<<~RUBY) + a, b, c = {a: 1}, {b: 2}, {c: 3} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = {a: 1} + b = {b: 2} + c = {c: 3} + RUBY + end + + it 'registers an offense when the right side has constants' do + expect_offense(<<~RUBY) + a, b, c = CONSTANT1, CONSTANT2, CONSTANT3 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = CONSTANT1 + b = CONSTANT2 + c = CONSTANT3 + RUBY + end + + it 'registers an offense when the right side has mixed expressions' do + expect_offense(<<~RUBY) + a, b, c = [1, 2], {a: 1}, CONSTANT3 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = [1, 2] + b = {a: 1} + c = CONSTANT3 + RUBY + end + + it 'registers an offense when the right side has methods with/without blocks' do + expect_offense(<<~RUBY) + a, b = foo { |a| puts a }, bar() + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = foo { |a| puts a } + b = bar() + RUBY + end + + it 'registers an offense when assignments must be reordered to ' \ + 'preserve meaning' do + expect_offense(<<~RUBY) + a, b = 1, a + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + b = a + a = 1 + RUBY + end + + it 'registers an offense when assigning to same variables in same order' do + expect_offense(<<~RUBY) + a, b = a, b + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = a + b = b + RUBY + end + + it 'registers an offense when right hand side has maps with blocks' do + expect_offense(<<~RUBY) + a, b = foo.map { |e| e.id }, bar.map { |e| e.id } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = foo.map { |e| e.id } + b = bar.map { |e| e.id } + RUBY + end + + it 'registers an offense when left hand side ends with an implicit variable' do + expect_offense(<<~RUBY) + array = [1, 2, 3] + a, b, c, = 8, 9, array + ^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + array = [1, 2, 3] + a = 8 + b = 9 + c = array + RUBY + end + + it 'registers an offense when right hand side has namespaced constants' do + expect_offense(<<~RUBY) + a, b = Float::INFINITY, Float::INFINITY + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = Float::INFINITY + b = Float::INFINITY + RUBY + end + + it 'registers an offense when assigning to namespaced constants' do + expect_offense(<<~RUBY) + Float::INFINITY, Float::INFINITY = 1, 2 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + Float::INFINITY = 1 + Float::INFINITY = 2 + RUBY + end + + it 'registers an offense with indices' do + expect_offense(<<~RUBY) + a[0], a[1] = a[1], a[2] + ^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a[0] = a[1] + a[1] = a[2] + RUBY + end + + it 'registers an offense with attributes when assignments must be ' \ + 'reordered to preserve meaning' do + expect_offense(<<~RUBY) + obj.attr1, obj.attr2 = obj.attr3, obj.attr1 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + obj.attr2 = obj.attr1 + obj.attr1 = obj.attr3 + RUBY + end + + it 'registers an offense with indices and attributes when assignments ' \ + 'must be reordered to preserve meaning' do + expect_offense(<<~RUBY) + obj.attr1, ary[0] = ary[1], obj.attr1 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + ary[0] = obj.attr1 + obj.attr1 = ary[1] + RUBY + end + + it 'registers an offense with indices of different variables' do + expect_offense(<<~RUBY) + a[0], a[1] = a[1], b[0] + ^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a[0] = a[1] + a[1] = b[0] + RUBY + end shared_examples('allowed') do |source| it "allows assignment of: #{source.gsub(/\s*\n\s*/, '; ')}" do @@ -93,482 +241,492 @@ it_behaves_like('allowed', 'self.a, self.b = self.b, self.a') it_behaves_like('allowed', 'self.a, self.b = b, a') - it 'highlights the entire expression' do + it 'corrects when the number of left hand variables matches ' \ + 'the number of right hand variables' do + expect_offense(<<~RUBY) + a, b, c = 1, 2, 3 + ^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + a = 1 + b = 2 + c = 3 + RUBY + end + + it 'corrects when the right variable is an array' do expect_offense(<<~RUBY) - a, b = 1, 2 - ^^^^^^^^^^^ Do not use parallel assignment. + a, b, c = ["1", "2", :c] + ^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. RUBY - end - it 'does not highlight the modifier statement' do - expect_offense(<<~RUBY) - a, b = 1, 2 if true - ^^^^^^^^^^^ Do not use parallel assignment. + expect_correction(<<~RUBY) + a = "1" + b = "2" + c = :c RUBY end - describe 'autocorrect' do - it 'corrects when the number of left hand variables matches ' \ - 'the number of right hand variables' do - new_source = autocorrect_source(<<~RUBY) - a, b, c = 1, 2, 3 - RUBY - - expect(new_source).to eq(<<~RUBY) - a = 1 - b = 2 - c = 3 - RUBY - end - - it 'corrects when the right variable is an array' do - new_source = autocorrect_source(<<~RUBY) - a, b, c = ["1", "2", :c] - RUBY + it 'corrects when the right variable is a word array' do + expect_offense(<<~RUBY) + a, b, c = %w(1 2 3) + ^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - a = "1" - b = "2" - c = :c - RUBY - end + expect_correction(<<~RUBY) + a = '1' + b = '2' + c = '3' + RUBY + end - it 'corrects when the right variable is a word array' do - new_source = autocorrect_source(<<~RUBY) - a, b, c = %w(1 2 3) - RUBY + it 'corrects when the right variable is a symbol array' do + expect_offense(<<~RUBY) + a, b, c = %i(a b c) + ^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - a = '1' - b = '2' - c = '3' - RUBY - end + expect_correction(<<~RUBY) + a = :a + b = :b + c = :c + RUBY + end - it 'corrects when the right variable is a symbol array' do - new_source = autocorrect_source(<<~RUBY) - a, b, c = %i(a b c) - RUBY + it 'corrects when assigning to method returns' do + expect_offense(<<~RUBY) + a, b = foo(), bar() + ^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - a = :a - b = :b - c = :c - RUBY - end + expect_correction(<<~RUBY) + a = foo() + b = bar() + RUBY + end - it 'corrects when assigning to method returns' do - new_source = autocorrect_source(<<~RUBY) - a, b = foo(), bar() - RUBY + it 'corrects when assigning from multiple methods with blocks' do + expect_offense(<<~RUBY) + a, b = foo() { |c| puts c }, bar() { |d| puts d } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - a = foo() - b = bar() - RUBY - end + expect_correction(<<~RUBY) + a = foo() { |c| puts c } + b = bar() { |d| puts d } + RUBY + end - it 'corrects when assigning from multiple methods with blocks' do - new_source = autocorrect_source(<<~RUBY) - a, b = foo() { |c| puts c }, bar() { |d| puts d } - RUBY + it 'corrects when using constants' do + expect_offense(<<~RUBY) + CONSTANT1, CONSTANT2 = CONSTANT3, CONSTANT4 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - a = foo() { |c| puts c } - b = bar() { |d| puts d } - RUBY - end + expect_correction(<<~RUBY) + CONSTANT1 = CONSTANT3 + CONSTANT2 = CONSTANT4 + RUBY + end - it 'corrects when using constants' do - new_source = autocorrect_source(<<~RUBY) - CONSTANT1, CONSTANT2 = CONSTANT3, CONSTANT4 - RUBY + it 'corrects when the expression is missing spaces' do + expect_offense(<<~RUBY) + a,b,c=1,2,3 + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - CONSTANT1 = CONSTANT3 - CONSTANT2 = CONSTANT4 - RUBY - end + expect_correction(<<~RUBY) + a = 1 + b = 2 + c = 3 + RUBY + end - it 'corrects when the expression is missing spaces' do - new_source = autocorrect_source(<<~RUBY) - a,b,c=1,2,3 - RUBY + it 'corrects when using single indentation' do + expect_offense(<<~RUBY) + def foo + a, b, c = 1, 2, 3 + ^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) + def foo a = 1 b = 2 c = 3 - RUBY - end + end + RUBY + end - it 'corrects when using single indentation' do - new_source = autocorrect_source(<<~RUBY) - def foo + it 'corrects when using nested indentation' do + expect_offense(<<~RUBY) + def foo + if true a, b, c = 1, 2, 3 + ^^^^^^^^^^^^^^^^^ Do not use parallel assignment. end - RUBY + end + RUBY - expect(new_source).to eq(<<~RUBY) - def foo + expect_correction(<<~RUBY) + def foo + if true a = 1 b = 2 c = 3 end - RUBY - end + end + RUBY + end - it 'corrects when using nested indentation' do - new_source = autocorrect_source(<<~RUBY) - def foo - if true - a, b, c = 1, 2, 3 - end - end - RUBY + it 'corrects when the expression uses a modifier if statement' do + expect_offense(<<~RUBY) + a, b = 1, 2 if foo + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - def foo - if true - a = 1 - b = 2 - c = 3 - end - end - RUBY - end + expect_correction(<<~RUBY) + if foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects when the expression uses a modifier if statement' do - new_source = autocorrect_source(<<~RUBY) + it 'corrects when the expression uses a modifier if statement ' \ + 'inside a method' do + expect_offense(<<~RUBY) + def foo a, b = 1, 2 if foo - RUBY + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) + def foo if foo a = 1 b = 2 end - RUBY - end + end + RUBY + end - it 'corrects when the expression uses a modifier if statement ' \ - 'inside a method' do - new_source = autocorrect_source(<<~RUBY) - def foo - a, b = 1, 2 if foo - end - RUBY + it 'corrects parallel assignment in if statements' do + expect_offense(<<~RUBY) + if foo + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) - def foo - if foo - a = 1 - b = 2 - end - end - RUBY - end + expect_correction(<<~RUBY) + if foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects parallel assignment in if statements' do - new_source = autocorrect_source(<<~RUBY) - if foo - a, b = 1, 2 - end - RUBY + it 'corrects when the expression uses a modifier unless statement' do + expect_offense(<<~RUBY) + a, b = 1, 2 unless foo + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - if foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + unless foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects when the expression uses a modifier unless statement' do - new_source = autocorrect_source(<<~RUBY) - a, b = 1, 2 unless foo - RUBY + it 'corrects parallel assignment in unless statements' do + expect_offense(<<~RUBY) + unless foo + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) - unless foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + unless foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects parallel assignment in unless statements' do - new_source = autocorrect_source(<<~RUBY) - unless foo - a, b = 1, 2 - end - RUBY + it 'corrects when the expression uses a modifier while statement' do + expect_offense(<<~RUBY) + a, b = 1, 2 while foo + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - unless foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + while foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects when the expression uses a modifier while statement' do - new_source = autocorrect_source(<<~RUBY) - a, b = 1, 2 while foo - RUBY + it 'corrects parallel assignment in while statements' do + expect_offense(<<~RUBY) + while foo + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) - while foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + while foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects parallel assignment in while statements' do - new_source = autocorrect_source(<<~RUBY) - while foo - a, b = 1, 2 - end - RUBY + it 'corrects when the expression uses a modifier until statement' do + expect_offense(<<~RUBY) + a, b = 1, 2 until foo + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - while foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + until foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects when the expression uses a modifier until statement' do - new_source = autocorrect_source(<<~RUBY) - a, b = 1, 2 until foo - RUBY + it 'corrects parallel assignment in until statements' do + expect_offense(<<~RUBY) + until foo + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) - until foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + until foo + a = 1 + b = 2 + end + RUBY + end - it 'corrects parallel assignment in until statements' do - new_source = autocorrect_source(<<~RUBY) - until foo - a, b = 1, 2 - end - RUBY + it 'corrects when the expression uses a modifier rescue statement' do + expect_offense(<<~RUBY) + a, b = 1, 2 rescue foo + ^^^^^^^^^^^ Do not use parallel assignment. + RUBY - expect(new_source).to eq(<<~RUBY) - until foo - a = 1 - b = 2 - end - RUBY - end + expect_correction(<<~RUBY) + begin + a = 1 + b = 2 + rescue + foo + end + RUBY + end - it 'corrects when the expression uses a modifier rescue statement' do - new_source = autocorrect_source(<<~RUBY) + it 'corrects parallel assignment inside rescue statements '\ + 'within method definitions' do + expect_offense(<<~RUBY) + def bar + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + rescue + 'foo' + end + RUBY + + expect_correction(<<~RUBY) + def bar + a = 1 + b = 2 + rescue + 'foo' + end + RUBY + end + + it 'corrects parallel assignment in rescue statements '\ + 'within begin ... rescue' do + expect_offense(<<~RUBY) + begin + a, b = 1, 2 + ^^^^^^^^^^^ Do not use parallel assignment. + rescue + 'foo' + end + RUBY + + expect_correction(<<~RUBY) + begin + a = 1 + b = 2 + rescue + 'foo' + end + RUBY + end + + it 'corrects when the expression uses a modifier rescue statement ' \ + 'as the only thing inside of a method' do + expect_offense(<<~RUBY) + def foo a, b = 1, 2 rescue foo - RUBY + ^^^^^^^^^^^ Do not use parallel assignment. + end + RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) + def foo + a = 1 + b = 2 + rescue + foo + end + RUBY + end + + it 'corrects when the expression uses a modifier rescue statement ' \ + 'inside of a method' do + expect_offense(<<~RUBY) + def foo + a, b = %w(1 2) rescue foo + ^^^^^^^^^^^^^^ Do not use parallel assignment. + something_else + end + RUBY + + expect_correction(<<~RUBY) + def foo begin - a = 1 - b = 2 + a = '1' + b = '2' rescue foo end - RUBY + something_else + end + RUBY + end + + it 'corrects when assignments must be reordered to avoid changing ' \ + 'meaning' do + expect_offense(<<~RUBY) + a, b, c, d = 1, a + 1, b + 1, a + b + c + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + RUBY + + expect_correction(<<~RUBY) + d = a + b + c + c = b + 1 + b = a + 1 + a = 1 + RUBY + end + + it 'allows more left variables than right variables' do + expect_no_offenses(<<~RUBY) + a, b, c, d = 1, 2 + RUBY + end + + it 'allows more right variables than left variables' do + expect_no_offenses(<<~RUBY) + a, b = 1, 2, 3 + RUBY + end + + it 'allows expanding an assigned var' do + expect_no_offenses(<<~RUBY) + foo = [1, 2, 3] + a, b, c = foo + RUBY + end + + describe 'using custom indentation width' do + let(:config) do + RuboCop::Config.new('Performance/ParallelAssignment' => { + 'Enabled' => true + }, + 'Layout/IndentationWidth' => { + 'Enabled' => true, + 'Width' => 3 + }) end - it 'corrects parallel assignment inside rescue statements '\ - 'within method definitions' do - new_source = autocorrect_source(<<~RUBY) - def bar - a, b = 1, 2 - rescue - 'foo' - end + it 'works with standard correction' do + expect_offense(<<~RUBY) + a, b, c = 1, 2, 3 + ^^^^^^^^^^^^^^^^^ Do not use parallel assignment. RUBY - expect(new_source).to eq(<<~RUBY) - def bar - a = 1 - b = 2 - rescue - 'foo' - end + expect_correction(<<~RUBY) + a = 1 + b = 2 + c = 3 RUBY end - it 'corrects parallel assignment in rescue statements '\ - 'within begin ... rescue' do - new_source = autocorrect_source(<<~RUBY) - begin - a, b = 1, 2 - rescue - 'foo' - end + it 'works with guard clauses' do + expect_offense(<<~RUBY) + a, b = 1, 2 if foo + ^^^^^^^^^^^ Do not use parallel assignment. RUBY - expect(new_source).to eq(<<~RUBY) - begin - a = 1 - b = 2 - rescue - 'foo' + expect_correction(<<~RUBY) + if foo + a = 1 + b = 2 end RUBY end - it 'corrects when the expression uses a modifier rescue statement ' \ - 'as the only thing inside of a method' do - new_source = autocorrect_source(<<~RUBY) - def foo - a, b = 1, 2 rescue foo - end + it 'works with rescue' do + expect_offense(<<~RUBY) + a, b = 1, 2 rescue foo + ^^^^^^^^^^^ Do not use parallel assignment. RUBY - expect(new_source).to eq(<<~RUBY) - def foo - a = 1 - b = 2 + expect_correction(<<~RUBY) + begin + a = 1 + b = 2 rescue - foo + foo end RUBY end - it 'corrects when the expression uses a modifier rescue statement ' \ - 'inside of a method' do - new_source = autocorrect_source(<<~RUBY) + it 'works with nesting' do + expect_offense(<<~RUBY) def foo - a, b = %w(1 2) rescue foo - something_else + if true + a, b, c = 1, 2, 3 + ^^^^^^^^^^^^^^^^^ Do not use parallel assignment. + end end RUBY - expect(new_source).to eq(<<~RUBY) + expect_correction(<<~RUBY) def foo - begin - a = '1' - b = '2' - rescue - foo - end - something_else + if true + a = 1 + b = 2 + c = 3 + end end RUBY end - - it 'corrects when assignments must be reordered to avoid changing ' \ - 'meaning' do - new_source = autocorrect_source(<<~RUBY) - a, b, c, d = 1, a + 1, b + 1, a + b + c - RUBY - - expect(new_source).to eq(<<~RUBY) - d = a + b + c - c = b + 1 - b = a + 1 - a = 1 - RUBY - end - - shared_examples('no correction') do |description, source| - context description do - it "does not change: #{source.gsub(/\s*\n\s*/, '; ')}" do - new_source = autocorrect_source(source) - expect(new_source).to eq(source) - end - end - end - - it_behaves_like 'no correction', - 'when there are more left variables than right variables', - 'a, b, c, d = 1, 2' - - it_behaves_like 'no correction', - 'when there are more right variables than left variables', - 'a, b = 1, 2, 3' - - it_behaves_like 'no correction', 'when expanding an assigned var', <<~RUBY - foo = [1, 2, 3] - a, b, c = foo - RUBY - - describe 'using custom indentation width' do - let(:config) do - RuboCop::Config.new('Performance/ParallelAssignment' => { - 'Enabled' => true - }, - 'Layout/IndentationWidth' => { - 'Enabled' => true, - 'Width' => 3 - }) - end - - it 'works with standard correction' do - new_source = autocorrect_source(<<~RUBY) - a, b, c = 1, 2, 3 - RUBY - - expect(new_source).to eq(<<~RUBY) - a = 1 - b = 2 - c = 3 - RUBY - end - - it 'works with guard clauses' do - new_source = autocorrect_source(<<~RUBY) - a, b = 1, 2 if foo - RUBY - - expect(new_source).to eq(<<~RUBY) - if foo - a = 1 - b = 2 - end - RUBY - end - - it 'works with rescue' do - new_source = autocorrect_source(<<~RUBY) - a, b = 1, 2 rescue foo - RUBY - - expect(new_source).to eq(<<~RUBY) - begin - a = 1 - b = 2 - rescue - foo - end - RUBY - end - - it 'works with nesting' do - new_source = autocorrect_source(<<~RUBY) - def foo - if true - a, b, c = 1, 2, 3 - end - end - RUBY - - expect(new_source).to eq(<<~RUBY) - def foo - if true - a = 1 - b = 2 - c = 3 - end - end - RUBY - end - end end end diff --git a/spec/rubocop/cop/style/parentheses_around_condition_spec.rb b/spec/rubocop/cop/style/parentheses_around_condition_spec.rb index a708b16ffc7..6f24cacf992 100644 --- a/spec/rubocop/cop/style/parentheses_around_condition_spec.rb +++ b/spec/rubocop/cop/style/parentheses_around_condition_spec.rb @@ -28,32 +28,8 @@ x += 1 while (x < 10) ^^^^^^^^ Don't use parentheses around the condition of a `while`. RUBY - end - - it 'accepts parentheses if there is no space between the keyword and (.' do - expect_no_offenses(<<~RUBY) - if(x > 5) then something end - do_something until(x > 5) - RUBY - end - it 'auto-corrects parentheses around condition' do - corrected = autocorrect_source(<<~RUBY) - if (x > 10) - elsif (x < 3) - end - unless (x > 10) - end - while (x > 10) - end - until (x > 10) - end - x += 1 if (x < 10) - x += 1 unless (x < 10) - x += 1 while (x < 10) - x += 1 until (x < 10) - RUBY - expect(corrected).to eq <<~RUBY + expect_correction(<<~RUBY) if x > 10 elsif x < 3 end @@ -65,25 +41,15 @@ end x += 1 if x < 10 x += 1 unless x < 10 - x += 1 while x < 10 x += 1 until x < 10 + x += 1 while x < 10 RUBY end - it 'accepts condition without parentheses' do + it 'accepts parentheses if there is no space between the keyword and (.' do expect_no_offenses(<<~RUBY) - if x > 10 - end - unless x > 10 - end - while x > 10 - end - until x > 10 - end - x += 1 if x < 10 - x += 1 unless x < 10 - x += 1 while x < 10 - x += 1 until x < 10 + if(x > 5) then something end + do_something until(x > 5) RUBY end @@ -95,7 +61,7 @@ expect_no_offenses('(a > b) && other ? one : two') end - it 'is not confused by unbalanced parentheses' do + it 'is not confused by parentheses in subexpression' do expect_no_offenses(<<~RUBY) if (a + b).c() end @@ -116,6 +82,10 @@ x if (a ? b : c) ^^^^^^^^^^^ Don't use parentheses around the condition of an `if`. RUBY + + expect_correction(<<~RUBY) + x if a ? b : c + RUBY end it 'does not blow up for empty if condition' do @@ -165,6 +135,11 @@ ^^^^^^^^^^^ Don't use parentheses around the condition of an `if`. end RUBY + + expect_correction(<<~RUBY) + if test = 10 + end + RUBY end it 'does not accept element assignment in condition surrounded with ' \ @@ -174,6 +149,11 @@ ^^^^^^^^^^^^^^ Don't use parentheses around the condition of an `if`. end RUBY + + expect_correction(<<~RUBY) + if test[0] = 10 + end + RUBY end end @@ -198,11 +178,18 @@ return true end RUBY + + expect_correction(<<~RUBY) + if x > 3 && x < 10 + return true + end + RUBY end end context 'parentheses in multiline conditions are not allowed' do let(:cop_config) { { 'AllowInMultilineConditions' => false } } + let(:trailing_whitespace) { ' ' } it 'registers an offense for parentheses around multiline condition' do expect_offense(<<~RUBY) @@ -214,6 +201,15 @@ return true end RUBY + + expect_correction(<<~RUBY) + if#{trailing_whitespace} + x > 3 && + x < 10 + + return true + end + RUBY end end end diff --git a/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb b/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb index a35cf04b017..16296243c89 100644 --- a/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb +++ b/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb @@ -28,7 +28,7 @@ let(:cop_config) { { 'PreferredDelimiters' => { 'foobar' => '()' } } } it 'raises an error when invalid configuration is specified' do - expect { inspect_source('%w[string]') }.to raise_error(ArgumentError) + expect { expect_no_offenses('%w[string]') }.to raise_error(ArgumentError) end end @@ -42,6 +42,21 @@ %(string) ^^^^^^^^^ `%`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %[string] + RUBY + end + + it 'registers an offense for a string with no content' do + expect_offense(<<~RUBY) + %() + ^^^ `%`-literals should be delimited by `[` and `]`. + RUBY + + expect_correction(<<~RUBY) + %[] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -57,10 +72,21 @@ %(#{[1].first}) ^^^^^^^^^^^^^^^ `%`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %[#{[1].first}] + RUBY end - it 'does not crash when the source contains invalid characters' do - expect { inspect_source('%{\x80}') }.not_to raise_error + it 'registers an offense when the source contains invalid characters' do + expect_offense(<<~'RUBY') + %{\x80} + ^^^^^^^ `%`-literals should be delimited by `[` and `]`. + RUBY + + expect_correction(<<~'RUBY') + %[\x80] + RUBY end end @@ -74,6 +100,10 @@ %q(string) ^^^^^^^^^^ `%q`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %q[string] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -94,6 +124,10 @@ %Q(string) ^^^^^^^^^^ `%Q`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %Q[string] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -109,6 +143,10 @@ %Q(#{[1].first}) ^^^^^^^^^^^^^^^^ `%Q`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %Q[#{[1].first}] + RUBY end end @@ -137,6 +175,10 @@ %w(some words) ^^^^^^^^^^^^^^ `%w`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %w[some words] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -155,6 +197,10 @@ %W(some words) ^^^^^^^^^^^^^^ `%W`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %W[some words] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -168,6 +214,10 @@ %W(#{[1].first}) ^^^^^^^^^^^^^^^^ `%W`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %W[#{[1].first}] + RUBY end end @@ -181,6 +231,10 @@ %r(regexp) ^^^^^^^^^^ `%r`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %r[regexp] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -194,6 +248,21 @@ %r(#{[1].first}) ^^^^^^^^^^^^^^^^ `%r`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %r[#{[1].first}] + RUBY + end + + it 'registers an offense for a regular expression with option' do + expect_offense(<<~RUBY) + %r(.*)i + ^^^^^^^ `%r`-literals should be delimited by `[` and `]`. + RUBY + + expect_correction(<<~RUBY) + %r[.*]i + RUBY end end @@ -212,6 +281,10 @@ %i(some symbols) ^^^^^^^^^^^^^^^^ `%i`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %i[some symbols] + RUBY end end @@ -225,6 +298,10 @@ %I(some words) ^^^^^^^^^^^^^^ `%I`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %I[some words] + RUBY end it 'registers an offense for other delimiters ' \ @@ -233,6 +310,10 @@ %I(#{[1].first}) ^^^^^^^^^^^^^^^^ `%I`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %I[#{[1].first}] + RUBY end end @@ -246,6 +327,10 @@ %s(symbol) ^^^^^^^^^^ `%s`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %s[symbol] + RUBY end end @@ -259,6 +344,10 @@ %x(command) ^^^^^^^^^^^ `%x`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~RUBY) + %x[command] + RUBY end it 'does not register an offense for other delimiters ' \ @@ -272,36 +361,27 @@ %x(#{[1].first}) ^^^^^^^^^^^^^^^^ `%x`-literals should be delimited by `[` and `]`. RUBY + + expect_correction(<<~'RUBY') + %x[#{[1].first}] + RUBY end end context 'auto-correct' do - it 'fixes a string' do - new_source = autocorrect_source('%(string)') - expect(new_source).to eq('%[string]') - end - - it 'fixes a string with no content' do - new_source = autocorrect_source('%()') - expect(new_source).to eq('%[]') - end - - it 'fixes a string array' do - new_source = autocorrect_source('%w(some words)') - expect(new_source).to eq('%w[some words]') - end - it 'fixes a string array in a scope' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) module Foo class Bar def baz %(one two) + ^^^^^^^^^^ `%`-literals should be delimited by `[` and `]`. end end end RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) module Foo class Bar def baz @@ -312,38 +392,16 @@ def baz RUBY end - it 'fixes a regular expression' do - original_source = '%r(.*)' - new_source = autocorrect_source(original_source) - expect(new_source).to eq('%r[.*]') - end - - it 'fixes a string with interpolation' do - original_source = '%Q|#{with_interpolation}|' - new_source = autocorrect_source(original_source) - expect(new_source).to eq('%Q[#{with_interpolation}]') - end - - it 'fixes a regular expression with interpolation' do - original_source = '%r|#{with_interpolation}|' - new_source = autocorrect_source(original_source) - expect(new_source).to eq('%r[#{with_interpolation}]') - end - - it 'fixes a regular expression with option' do - original_source = '%r(.*)i' - new_source = autocorrect_source(original_source) - expect(new_source).to eq('%r[.*]i') - end - it 'preserves line breaks when fixing a multiline array' do - new_source = autocorrect_source(<<~RUBY) + expect_offense(<<~RUBY) %w( + ^^^ `%w`-literals should be delimited by `[` and `]`. some words ) RUBY - expect(new_source).to eq(<<~RUBY) + + expect_correction(<<~RUBY) %w[ some words @@ -352,50 +410,64 @@ def baz end it 'preserves indentation when correcting a multiline array' do - original_source = <<-RUBY.strip_margin('|') + expect_offense(<<-RUBY.strip_margin('|')) | array = %w( + | ^^^ `%w`-literals should be delimited by `[` and `]`. | first | second | ) RUBY - corrected_source = <<-RUBY.strip_margin('|') + + expect_correction(<<-RUBY.strip_margin('|')) | array = %w[ | first | second | ] RUBY - new_source = autocorrect_source(original_source) - expect(new_source).to eq(corrected_source) end it 'preserves irregular indentation when correcting a multiline array' do - original_source = <<~RUBY + expect_offense(<<~RUBY) array = %w( + ^^^ `%w`-literals should be delimited by `[` and `]`. first second ) RUBY - corrected_source = <<~RUBY + + expect_correction(<<~RUBY) array = %w[ first second ] RUBY - new_source = autocorrect_source(original_source) - expect(new_source).to eq(corrected_source) end shared_examples 'escape characters' do |percent_literal| - it "corrects #{percent_literal} with \\n in it" do - new_source = autocorrect_source("#{percent_literal}{\n}") + let(:tab) { "\t" } - expect(new_source).to eq("#{percent_literal}[\n]") + it "corrects #{percent_literal} with \\n in it" do + expect_offense(<<~RUBY, percent_literal: percent_literal) + %{percent_literal}{ + ^{percent_literal}^ `#{percent_literal}`-literals should be delimited by `[` and `]`. + } + RUBY + + expect_correction(<<~RUBY) + #{percent_literal}[ + ] + RUBY end it "corrects #{percent_literal} with \\t in it" do - new_source = autocorrect_source("#{percent_literal}{\t}") - - expect(new_source).to eq("#{percent_literal}[\t]") + expect_offense(<<~RUBY, percent_literal: percent_literal, tab: tab) + %{percent_literal}{%{tab}} + ^{percent_literal}^^{tab}^ `#{percent_literal}`-literals should be delimited by `[` and `]`. + RUBY + + expect_correction(<<~RUBY) + #{percent_literal}[\t] + RUBY end end diff --git a/spec/rubocop/cop/style/percent_q_literals_spec.rb b/spec/rubocop/cop/style/percent_q_literals_spec.rb index 2f77af9f684..99e0f7f5ba3 100644 --- a/spec/rubocop/cop/style/percent_q_literals_spec.rb +++ b/spec/rubocop/cop/style/percent_q_literals_spec.rb @@ -36,11 +36,10 @@ %Q(hi) ^^^ Do not use `%Q` unless interpolation is needed. Use `%q`. RUBY - end - it 'auto-corrects' do - new_source = autocorrect_source('%Q(hi)') - expect(new_source).to eq('%q(hi)') + expect_correction(<<~RUBY) + %q(hi) + RUBY end include_examples 'accepts quote characters' @@ -70,17 +69,16 @@ %q(hi) ^^^ Use `%Q` instead of `%q`. RUBY + + expect_correction(<<~RUBY) + %Q(hi) + RUBY end it 'accepts %Q' do expect_no_offenses('%Q(hi)') end - it 'auto-corrects' do - new_source = autocorrect_source('%q[hi]') - expect(new_source).to eq('%Q[hi]') - end - include_examples 'accepts quote characters' include_examples 'accepts any q string with backslash t' end @@ -97,12 +95,6 @@ expect_no_offenses('%q(#{1 + 2})') end - it 'does not auto-correct' do - source = '%q(#{1 + 2})' - new_source = autocorrect_source(source) - expect(new_source).to eq(source) - end - include_examples 'accepts quote characters' end end diff --git a/spec/rubocop/cop/style/perl_backrefs_spec.rb b/spec/rubocop/cop/style/perl_backrefs_spec.rb index fd820748ffe..5200e379863 100644 --- a/spec/rubocop/cop/style/perl_backrefs_spec.rb +++ b/spec/rubocop/cop/style/perl_backrefs_spec.rb @@ -8,15 +8,31 @@ puts $1 ^^ Avoid the use of Perl-style backrefs. RUBY + + expect_correction(<<~RUBY) + puts Regexp.last_match(1) + RUBY end - it 'auto-corrects $1 to Regexp.last_match(1)' do - new_source = autocorrect_source('$1') - expect(new_source).to eq('Regexp.last_match(1)') + it 'registers an offense for $9' do + expect_offense(<<~RUBY) + $9 + ^^ Avoid the use of Perl-style backrefs. + RUBY + + expect_correction(<<~RUBY) + Regexp.last_match(9) + RUBY end it 'auto-corrects #$1 to #{Regexp.last_match(1)}' do - new_source = autocorrect_source('"#$1"') - expect(new_source).to eq('"#{Regexp.last_match(1)}"') + expect_offense(<<~'RUBY') + "#$1" + ^^ Avoid the use of Perl-style backrefs. + RUBY + + expect_correction(<<~'RUBY') + "#{Regexp.last_match(1)}" + RUBY end end diff --git a/spec/rubocop/cop/style/proc_spec.rb b/spec/rubocop/cop/style/proc_spec.rb index 73bbb81af21..4352b818de2 100644 --- a/spec/rubocop/cop/style/proc_spec.rb +++ b/spec/rubocop/cop/style/proc_spec.rb @@ -8,6 +8,10 @@ f = Proc.new { |x| puts x } ^^^^^^^^ Use `proc` instead of `Proc.new`. RUBY + + expect_correction(<<~RUBY) + f = proc { |x| puts x } + RUBY end it 'registers an offense for ::Proc.new' do @@ -15,22 +19,17 @@ f = ::Proc.new { |x| puts x } ^^^^^^^^^^ Use `proc` instead of `Proc.new`. RUBY - end - it 'accepts the proc method' do - expect_no_offenses('f = proc { |x| puts x }') + expect_correction(<<~RUBY) + f = proc { |x| puts x } + RUBY end - it 'accepts the Proc.new call outside of block' do + it 'accepts the Proc.new call without block' do expect_no_offenses('p = Proc.new') end it 'accepts the ::Proc.new call without block' do expect_no_offenses('p = ::Proc.new') end - - it 'auto-corrects Proc.new to proc' do - corrected = autocorrect_source('Proc.new { test }') - expect(corrected).to eq 'proc { test }' - end end