240 lines
6.6 KiB
Ruby
240 lines
6.6 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'fast_spec_helper'
|
||
|
require 'rspec-parameterized'
|
||
|
require 'rubocop/rspec/shared_contexts'
|
||
|
require 'stringio'
|
||
|
|
||
|
require_relative '../../../rubocop/formatter/graceful_formatter'
|
||
|
require_relative '../../../rubocop/todo_dir'
|
||
|
|
||
|
RSpec.describe RuboCop::Formatter::GracefulFormatter, :isolated_environment do
|
||
|
# Set by :isolated_environment
|
||
|
let(:todo_dir) { RuboCop::TodoDir.new("#{Dir.pwd}/.rubocop_todo") }
|
||
|
let(:stdout) { StringIO.new }
|
||
|
|
||
|
subject(:formatter) { described_class.new(stdout) }
|
||
|
|
||
|
shared_examples 'summary reporting' do |inspected:, offenses: 0, silenced: 0|
|
||
|
it "reports summary with #{inspected} inspected, #{offenses} offenses, #{silenced} silenced" do
|
||
|
expect(stdout.string)
|
||
|
.to match(/Inspecting #{inspected} files/)
|
||
|
.and match(/#{inspected} files inspected/)
|
||
|
|
||
|
if offenses > 0
|
||
|
expect(stdout.string).to match(/Offenses:/)
|
||
|
expect(stdout.string).to match(/#{offenses} offenses detected/)
|
||
|
else
|
||
|
expect(stdout.string).not_to match(/Offenses:/)
|
||
|
expect(stdout.string).to match(/no offenses detected/)
|
||
|
end
|
||
|
|
||
|
if silenced > 0
|
||
|
expect(stdout.string).to match(/Silenced offenses:/)
|
||
|
expect(stdout.string).to match(/#{silenced} offenses silenced/)
|
||
|
else
|
||
|
expect(stdout.string).not_to match(/Silenced offenses:/)
|
||
|
expect(stdout.string).not_to match(/offenses silenced/)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'with offenses' do
|
||
|
let(:offense1) { fake_offense('Cop1') }
|
||
|
let(:offense2) { fake_offense('Cop2') }
|
||
|
|
||
|
before do
|
||
|
FileUtils.touch('.rubocop_todo.yml')
|
||
|
|
||
|
File.write('.rubocop.yml', <<~YAML)
|
||
|
inherit_from:
|
||
|
<% Dir.glob('.rubocop_todo/**/*.yml').each do |rubocop_todo_yaml| %>
|
||
|
- '<%= rubocop_todo_yaml %>'
|
||
|
<% end %>
|
||
|
- '.rubocop_todo.yml'
|
||
|
|
||
|
AllCops:
|
||
|
NewCops: enable # Avoiding RuboCop warnings
|
||
|
YAML
|
||
|
|
||
|
# These cops are unknown and would raise an validation error
|
||
|
allow(RuboCop::Cop::Registry.global).to receive(:contains_cop_matching?)
|
||
|
.and_return(true)
|
||
|
end
|
||
|
|
||
|
context 'with active only' do
|
||
|
before do
|
||
|
formatter.started(%w[a.rb b.rb])
|
||
|
formatter.file_finished('a.rb', [offense1])
|
||
|
formatter.file_finished('b.rb', [offense2])
|
||
|
formatter.finished(%w[a.rb b.rb])
|
||
|
end
|
||
|
|
||
|
it_behaves_like 'summary reporting', inspected: 2, offenses: 2
|
||
|
end
|
||
|
|
||
|
context 'with silenced only' do
|
||
|
before do
|
||
|
todo_dir.write('Cop1', <<~YAML)
|
||
|
---
|
||
|
Cop1:
|
||
|
Details: grace period
|
||
|
YAML
|
||
|
|
||
|
File.write('.rubocop_todo.yml', <<~YAML)
|
||
|
---
|
||
|
Cop2:
|
||
|
Details: grace period
|
||
|
YAML
|
||
|
|
||
|
formatter.started(%w[a.rb b.rb])
|
||
|
formatter.file_finished('a.rb', [offense1])
|
||
|
formatter.file_finished('b.rb', [offense2])
|
||
|
formatter.finished(%w[a.rb b.rb])
|
||
|
end
|
||
|
|
||
|
it_behaves_like 'summary reporting', inspected: 2, silenced: 2
|
||
|
end
|
||
|
|
||
|
context 'with active and silenced' do
|
||
|
before do
|
||
|
todo_dir.write('Cop1', <<~YAML)
|
||
|
---
|
||
|
Cop1:
|
||
|
Details: grace period
|
||
|
YAML
|
||
|
|
||
|
formatter.started(%w[a.rb b.rb])
|
||
|
formatter.file_finished('a.rb', [offense1, offense2])
|
||
|
formatter.file_finished('b.rb', [offense2, offense1, offense1])
|
||
|
formatter.finished(%w[a.rb b.rb])
|
||
|
end
|
||
|
|
||
|
it_behaves_like 'summary reporting', inspected: 2, offenses: 2, silenced: 3
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'without offenses' do
|
||
|
before do
|
||
|
formatter.started(%w[a.rb b.rb])
|
||
|
formatter.file_finished('a.rb', [])
|
||
|
formatter.file_finished('b.rb', [])
|
||
|
formatter.finished(%w[a.rb b.rb])
|
||
|
end
|
||
|
|
||
|
it_behaves_like 'summary reporting', inspected: 2
|
||
|
end
|
||
|
|
||
|
context 'without files to inspect' do
|
||
|
before do
|
||
|
formatter.started([])
|
||
|
formatter.finished([])
|
||
|
end
|
||
|
|
||
|
it_behaves_like 'summary reporting', inspected: 0
|
||
|
end
|
||
|
|
||
|
context 'with missing @total_offense_count' do
|
||
|
it 'raises an error' do
|
||
|
formatter.started(%w[a.rb])
|
||
|
|
||
|
if formatter.instance_variable_defined?(:@total_offense_count)
|
||
|
formatter.remove_instance_variable(:@total_offense_count)
|
||
|
end
|
||
|
|
||
|
expect do
|
||
|
formatter.finished(%w[a.rb])
|
||
|
end.to raise_error(/RuboCop has changed its internals/)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '.adjusted_exit_status' do
|
||
|
using RSpec::Parameterized::TableSyntax
|
||
|
|
||
|
success = RuboCop::CLI::STATUS_SUCCESS
|
||
|
offenses = RuboCop::CLI::STATUS_OFFENSES
|
||
|
error = RuboCop::CLI::STATUS_ERROR
|
||
|
|
||
|
subject { described_class.adjusted_exit_status(status) }
|
||
|
|
||
|
where(:active_offenses, :status, :adjusted_status) do
|
||
|
0 | success | success
|
||
|
0 | offenses | success
|
||
|
1 | offenses | offenses
|
||
|
0 | error | error
|
||
|
1 | error | error
|
||
|
# impossible cases
|
||
|
1 | success | success
|
||
|
end
|
||
|
|
||
|
with_them do
|
||
|
around do |example|
|
||
|
described_class.active_offenses = active_offenses
|
||
|
example.run
|
||
|
ensure
|
||
|
described_class.active_offenses = 0
|
||
|
end
|
||
|
|
||
|
it { is_expected.to eq(adjusted_status) }
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '.grace_period?' do
|
||
|
let(:cop_name) { 'Cop/Name' }
|
||
|
|
||
|
subject { described_class.grace_period?(cop_name, config) }
|
||
|
|
||
|
context 'with Details in config' do
|
||
|
let(:config) { { 'Details' => 'grace period' } }
|
||
|
|
||
|
it { is_expected.to eq(true) }
|
||
|
end
|
||
|
|
||
|
context 'with unknown value for Details in config' do
|
||
|
let(:config) { { 'Details' => 'unknown' } }
|
||
|
|
||
|
specify do
|
||
|
expect { is_expected.to eq(false) }
|
||
|
.to output(/#{cop_name}: Unhandled value "unknown" for `Details` key./)
|
||
|
.to_stderr
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'with empty config' do
|
||
|
let(:config) { {} }
|
||
|
|
||
|
it { is_expected.to eq(false) }
|
||
|
end
|
||
|
|
||
|
context 'without Details in config' do
|
||
|
let(:config) { { 'Exclude' => false } }
|
||
|
|
||
|
it { is_expected.to eq(false) }
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '.grace_period_key_value' do
|
||
|
subject { described_class.grace_period_key_value }
|
||
|
|
||
|
it { is_expected.to eq('Details: grace period') }
|
||
|
end
|
||
|
|
||
|
def fake_offense(cop_name)
|
||
|
# rubocop:disable RSpec/VerifiedDoubles
|
||
|
double(:offense,
|
||
|
cop_name: cop_name,
|
||
|
corrected?: false,
|
||
|
correctable?: false,
|
||
|
severity: double(:severity, name: 'convention', code: :C),
|
||
|
line: 5,
|
||
|
column: 23,
|
||
|
real_column: 23,
|
||
|
corrected_with_todo?: false,
|
||
|
message: "#{cop_name} message",
|
||
|
location: double(:location, source_line: 'line', first_line: 1, last_line: 2),
|
||
|
highlighted_area: double(:highlighted_area, begin_pos: 1, size: 2)
|
||
|
)
|
||
|
# rubocop:enable RSpec/VerifiedDoubles
|
||
|
end
|
||
|
end
|