Skip to content

Commit

Permalink
Refactor config shared context. Simplify some specs.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcandre authored and bbatsov committed May 21, 2020
1 parent 4d694e3 commit 3c91822
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 106 deletions.
70 changes: 55 additions & 15 deletions lib/rubocop/rspec/shared_contexts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,66 @@
end
end

# `cop_config` must be declared with #let.
RSpec.shared_context 'config', :config do
let(:config) do
# Module#<
raise '`config` must be used in `describe SomeCopClass do .. end`' unless described_class < RuboCop::Cop::Cop

hash = { 'AllCops' => { 'TargetRubyVersion' => ruby_version } }
hash['AllCops']['TargetRailsVersion'] = rails_version if rails_version
if respond_to?(:cop_config)
cop_name = described_class.cop_name
hash[cop_name] = RuboCop::ConfigLoader
.default_configuration[cop_name]
.merge('Enabled' => true) # in case it is 'pending'
.merge(cop_config)
# This context assumes nothing and defines `cop`, among others.
RSpec.shared_context 'config', :config do # rubocop:disable Metrics/BlockLength
### Meant to be overriden at will

let(:source) { 'code = {some: :ruby}' }

let(:cop_class) do
if described_class.is_a?(Class) && described_class < RuboCop::Cop::Cop
described_class
else
RuboCop::Cop::Cop
end
end

let(:cop_config) { {} }

let(:other_cops) { {} }

let(:cop_options) { {} }

### Utilities

def source_range(range, buffer: source_buffer)
Parser::Source::Range.new(buffer, range.begin,
range.exclude_end? ? range.end : range.end + 1)
end

hash = other_cops.merge hash if respond_to?(:other_cops)
### Usefull intermediary steps (less likely to be overriden)

let(:processed_source) { parse_source(source, 'test') }

let(:source_buffer) { processed_source.buffer }

let(:all_cops_config) do
rails = { 'TargetRubyVersion' => ruby_version }
rails['TargetRailsVersion'] = rails_version if rails_version
rails
end

let(:cur_cop_config) do
RuboCop::ConfigLoader
.default_configuration.for_cop(cop_class)
.merge({
'Enabled' => true, # in case it is 'pending'
'AutoCorrect' => true # in case defaults set it to false
})
.merge(cop_config)
end

let(:config) do
hash = { 'AllCops' => all_cops_config,
cop_class.cop_name => cur_cop_config }.merge!(other_cops)

RuboCop::Config.new(hash, "#{Dir.pwd}/.rubocop.yml")
end

let(:cop) do
cop_class.new(config, cop_options)
.tap { |cop| cop.processed_source = processed_source }
end
end

RSpec.shared_context 'mock console output' do
Expand Down
4 changes: 2 additions & 2 deletions spec/rubocop/cop/alignment_corrector_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::AlignmentCorrector do
let(:cop) { RuboCop::Cop::Test::AlignmentDirective.new }
RSpec.describe RuboCop::Cop::AlignmentCorrector, :config do
let(:cop_class) { RuboCop::Cop::Test::AlignmentDirective }

describe '#correct' do
context 'simple indentation' do
Expand Down
94 changes: 45 additions & 49 deletions spec/rubocop/cop/cop_spec.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Cop do
subject(:cop) { described_class.new }

RSpec.describe RuboCop::Cop::Cop, :config do
let(:location) do
source_buffer = Parser::Source::Buffer.new('test', 1)
source_buffer.source = "a\n"
Parser::Source::Range.new(source_buffer, 0, 1)
source_range(0...1)
end

it 'initially has 0 offenses' do
Expand Down Expand Up @@ -90,32 +86,41 @@
.to output(/Warning: Invalid severity 'superbad'./).to_stderr
end

it 'will set offense as disabled if ignore_disable_comments is false' do
comment_config = instance_double(RuboCop::CommentConfig,
cop_enabled_at_line?: false)
processed_source = instance_double(RuboCop::ProcessedSource,
comment_config: comment_config)
cop.processed_source = processed_source
cop.instance_variable_set(:@options, ignore_disable_comments: false)
cop.add_offense(nil, location: location, message: 'message')
expect(cop.offenses.first.status).to eq :disabled
end
context 'when disabled by a comment' do
subject(:offense_status) do
cop.add_offense(nil, location: location, message: 'message')
cop.offenses.first.status
end

it 'will not set offense as disabled if ignore_disable_comments is true' do
comment_config = instance_double(RuboCop::CommentConfig,
cop_enabled_at_line?: false)
processed_source = instance_double(RuboCop::ProcessedSource,
comment_config: comment_config)
cop.processed_source = processed_source
cop.instance_variable_set(:@options, ignore_disable_comments: true)
cop.add_offense(nil, location: location, message: 'message')
expect(cop.offenses.first.status).not_to eq :disabled
before do
allow(processed_source.comment_config).to receive(:cop_enabled_at_line?)
.and_return(false)
end

context 'ignore_disable_comments is false' do
let(:cop_options) { { ignore_disable_comments: false } }

it 'will set offense as disabled' do
expect(offense_status).to eq :disabled
end
end

context 'ignore_disable_comments is true' do
let(:cop_options) { { ignore_disable_comments: true } }

it 'will not set offense as disabled' do
expect(offense_status).not_to eq :disabled
end
end
end

it 'registers offense with its name' do
cop = RuboCop::Cop::Style::For.new
cop.add_offense(nil, location: location, message: 'message')
expect(cop.offenses.first.cop_name).to eq('Style/For')
describe 'for a cop with a name' do
let(:cop_class) { RuboCop::Cop::Style::For }

it 'registers offense with its name' do
cop.add_offense(nil, location: location, message: 'message')
expect(cop.offenses.first.cop_name).to eq('Style/For')
end
end

describe 'setting of Offense#corrected attribute' do
Expand Down Expand Up @@ -161,7 +166,7 @@
end

context 'when cop supports autocorrection' do
let(:cop) { RuboCop::Cop::Style::Alias.new }
let(:cop_class) { RuboCop::Cop::Style::Alias }

context 'when offense was corrected' do
before do
Expand Down Expand Up @@ -201,24 +206,22 @@
end

context 'with no submodule' do
subject(:cop) { described_class }

it('has right name') { expect(cop.cop_name).to eq('Cop/Cop') }
it('has right department') { expect(cop.department).to eq(:Cop) }
it('has right name') { expect(cop_class.cop_name).to eq('Cop/Cop') }
it('has right department') { expect(cop_class.department).to eq(:Cop) }
end

context 'with style cops' do
subject(:cop) { RuboCop::Cop::Style::For }
let(:cop_class) { RuboCop::Cop::Style::For }

it('has right name') { expect(cop.cop_name).to eq('Style/For') }
it('has right department') { expect(cop.department).to eq(:Style) }
it('has right name') { expect(cop_class.cop_name).to eq('Style/For') }
it('has right department') { expect(cop_class.department).to eq(:Style) }
end

context 'with lint cops' do
subject(:cop) { RuboCop::Cop::Lint::Loop }
let(:cop_class) { RuboCop::Cop::Lint::Loop }

it('has right name') { expect(cop.cop_name).to eq('Lint/Loop') }
it('has right department') { expect(cop.department).to eq(:Lint) }
it('has right name') { expect(cop_class.cop_name).to eq('Lint/Loop') }
it('has right department') { expect(cop_class.department).to eq(:Lint) }
end

describe 'Registry' do
Expand Down Expand Up @@ -262,8 +265,6 @@

subject { cop.autocorrect? }

let(:config) { RuboCop::Config.new({}) }
let(:cop) { described_class.new(config, options) }
let(:support_autocorrect) { true }
let(:disable_uncorrectable) { false }

Expand All @@ -279,7 +280,7 @@
end

context 'when the option is given' do
let(:options) { { auto_correct: true } }
let(:cop_options) { { auto_correct: true } }

it { is_expected.to be(true) }

Expand All @@ -296,9 +297,7 @@
end

context 'when the cop is set to not autocorrect' do
let(:config) do
RuboCop::Config.new('Cop/Cop' => { 'AutoCorrect' => false })
end
let(:cop_options) { { 'AutoCorrect' => false } }

it { is_expected.to be(false) }
end
Expand All @@ -308,9 +307,6 @@
describe '#safe_autocorrect?' do
subject { cop.safe_autocorrect? }

let(:config) { RuboCop::Config.new('Cop/Cop' => cop_config) }
let(:cop) { described_class.new(config) }

context 'when cop is declared unsafe' do
let(:cop_config) { { 'Safe' => false } }

Expand Down
18 changes: 5 additions & 13 deletions spec/rubocop/cop/lint/redundant_cop_disable_directive_spec.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::RedundantCopDisableDirective do
RSpec.describe RuboCop::Cop::Lint::RedundantCopDisableDirective, :config do
describe '.check' do
let(:cop) do
cop = described_class.new
cop.instance_variable_get(:@options)[:auto_correct] = true
cop.processed_source = processed_source
cop
end
let(:processed_source) do
RuboCop::ProcessedSource.new(source, ruby_version)
end
let(:cop_options) { { auto_correct: true } }
let(:comments) { processed_source.comments }
let(:corrected_source) do
RuboCop::Cop::Corrector
Expand Down Expand Up @@ -246,9 +238,9 @@
'Unnecessary disabling of `Lint/Debugger`.'])
expect(cop.highlights).to eq(%w[ClassLength Debugger])
expect($stderr.string).to eq(<<~OUTPUT)
(string): Warning: no department given for MethodLength.
(string): Warning: no department given for ClassLength.
(string): Warning: no department given for Debugger.
test: Warning: no department given for MethodLength.
test: Warning: no department given for ClassLength.
test: Warning: no department given for Debugger.
OUTPUT
end
end
Expand Down
13 changes: 5 additions & 8 deletions spec/rubocop/cop/style/guard_clause_spec.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::GuardClause do
let(:cop) { described_class.new(config) }
let(:config) do
RuboCop::Config.new(
RSpec.describe RuboCop::Cop::Style::GuardClause, :config do
let(:other_cops) do
{
'Layout/LineLength' => {
'Enabled' => line_length_enabled,
'Max' => 80
},
'Style/GuardClause' => cop_config
)
}
}
end
let(:line_length_enabled) { true }
let(:cop_config) { {} }

shared_examples 'reports offense' do |body|
it 'reports an offense if method body is if / unless without else' do
Expand Down
30 changes: 11 additions & 19 deletions spec/rubocop/formatter/clang_style_formatter_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Formatter::ClangStyleFormatter do
RSpec.describe RuboCop::Formatter::ClangStyleFormatter, :config do
subject(:formatter) { described_class.new(output) }

let(:output) { StringIO.new }
Expand All @@ -13,16 +13,13 @@
'This is a message.', 'CopName', status)
end

let(:source) { ('aa'..'az').to_a.join($RS) }

let(:location) do
source_buffer = Parser::Source::Buffer.new('test', 1)
source_buffer.source = "a\n"
Parser::Source::Range.new(source_buffer, 0, 1)
source_range(0...1)
end

it 'displays text containing the offending source line' do
cop = RuboCop::Cop::Cop.new
source_buffer = Parser::Source::Buffer.new('test', 1)
source_buffer.source = ('aa'..'az').to_a.join($RS)
cop.add_offense(
nil,
location: Parser::Source::Range.new(source_buffer, 0, 2),
Expand All @@ -46,10 +43,9 @@
end

context 'when the source line is blank' do
let(:source) { [' ', 'yaba'].join($RS) }

it 'does not display offending source line' do
cop = RuboCop::Cop::Cop.new
source_buffer = Parser::Source::Buffer.new('test', 1)
source_buffer.source = [' ', 'yaba'].join($RS)
cop.add_offense(
nil,
location: Parser::Source::Range.new(source_buffer, 0, 2),
Expand All @@ -72,21 +68,17 @@
end

context 'when the offending source spans multiple lines' do
it 'displays the first line with ellipses' do
source = <<~RUBY
let(:source) do
<<~RUBY
do_something([this,
is,
target])
RUBY
end

source_buffer = Parser::Source::Buffer.new('test', 1)
source_buffer.source = source

location = Parser::Source::Range.new(source_buffer,
source.index('['),
source.index(']') + 1)
it 'displays the first line with ellipses' do
location = source_range(source.index('[')..source.index(']'))

cop = RuboCop::Cop::Cop.new
cop.add_offense(nil, location: location, message: 'message 1')

formatter.report_file('test', cop.offenses)
Expand Down

0 comments on commit 3c91822

Please sign in to comment.