require 'pathname' require_relative '../../spec_helper' require_lib 'reek/spec' RSpec.describe Reek::Spec::ShouldReekOf do describe 'smell type check' do let(:ruby) { 'def double_thing() @other.thing.foo + @other.thing.foo end' } it 'reports duplicate calls' do expect(ruby).to reek_of(:Duplication) end it 'does not report any feature envy' do expect(ruby).not_to reek_of(:FeatureEnvy) end end describe 'different sources of input' do context 'checking code in a string' do let(:clean_code) { 'def good() true; end' } let(:matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, name: 'y') } let(:smelly_code) { 'def x() y = 4; end' } it 'matches a smelly String' do expect(matcher.matches?(smelly_code)).to be_truthy end it 'doesnt match a fragrant String' do expect(matcher.matches?(clean_code)).to be_falsey end end context 'checking code in a File' do let(:clean_file) { Pathname.glob("#{SAMPLES_PATH}/three_clean_files/*.rb").first } let(:matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, name: '@s') } let(:smelly_file) { Pathname.glob("#{SAMPLES_PATH}/two_smelly_files/*.rb").first } it 'matches a smelly file' do expect(matcher.matches?(smelly_file)).to be_truthy end it 'doesnt match a fragrant file' do expect(matcher.matches?(clean_file)).to be_falsey end end end describe 'smell types and smell details' do context 'passing in smell_details with unknown parameter name' do let(:matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, foo: 'y') } let(:smelly_code) { 'def x() y = 4; end' } it 'raises ArgumentError' do expect { matcher.matches?(smelly_code) }.to raise_error(ArgumentError) end end context 'both are matching' do let(:smelly_code) { 'def x() y = 4; end' } let(:matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, name: 'y') } it 'is truthy' do expect(matcher.matches?(smelly_code)).to be_truthy end end context 'no smell_type is matching' do let(:smelly_code) { 'def dummy() y = 4; end' } let(:falsey_matcher) { Reek::Spec::ShouldReekOf.new(:FeatureEnvy, name: 'y') } let(:truthy_matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, name: 'y') } it 'is falsey' do expect(falsey_matcher.matches?(smelly_code)).to be_falsey end it 'sets the proper error message' do falsey_matcher.matches?(smelly_code) expect(falsey_matcher.failure_message).to\ match('Expected string to reek of FeatureEnvy, but it didn\'t') end it 'sets the proper error message when negated' do truthy_matcher.matches?(smelly_code) expect(truthy_matcher.failure_message_when_negated).to\ match('Expected string not to reek of UncommunicativeVariableName, but it did') end end context 'smell type is matching but smell details are not' do let(:smelly_code) { 'def dummy() y = 4; end' } let(:matcher) { Reek::Spec::ShouldReekOf.new(:UncommunicativeVariableName, name: 'x') } it 'is falsey' do expect(matcher.matches?(smelly_code)).to be_falsey end it 'sets the proper error message' do matcher.matches?(smelly_code) expect(matcher.failure_message).to\ match('Expected string to reek of UncommunicativeVariableName (which it did) with '\ 'smell details {:name=>"x"}, which it didn\'t') end it 'sets the proper error message when negated' do matcher.matches?(smelly_code) expect(matcher.failure_message_when_negated).to\ match('Expected string not to reek of UncommunicativeVariableName with smell '\ 'details {:name=>"x"}, but it did') end end end end