reek 4.4.2 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/CHANGELOG.md +16 -0
  4. data/CONTRIBUTING.md +52 -23
  5. data/README.md +16 -3
  6. data/ataru_setup.rb +1 -1
  7. data/docs/API.md +1 -4
  8. data/docs/How-reek-works-internally.md +5 -5
  9. data/docs/Style-Guide.md +7 -0
  10. data/features/command_line_interface/options.feature +1 -0
  11. data/features/command_line_interface/show_progress.feature +33 -0
  12. data/features/configuration_files/masking_smells.feature +0 -1
  13. data/features/configuration_via_source_comments/erroneous_source_comments.feature +18 -4
  14. data/features/configuration_via_source_comments/well_formed_source_comments.feature +116 -0
  15. data/features/step_definitions/sample_file_steps.rb +5 -0
  16. data/features/todo_list.feature +42 -14
  17. data/lib/reek.rb +1 -1
  18. data/lib/reek/cli/application.rb +5 -0
  19. data/lib/reek/cli/command/report_command.rb +6 -1
  20. data/lib/reek/cli/command/todo_list_command.rb +1 -2
  21. data/lib/reek/cli/options.rb +19 -3
  22. data/lib/reek/code_comment.rb +83 -11
  23. data/lib/reek/configuration/configuration_validator.rb +2 -2
  24. data/lib/reek/errors/bad_detector_in_comment_error.rb +35 -0
  25. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +34 -0
  26. data/lib/reek/examiner.rb +36 -14
  27. data/lib/reek/report.rb +28 -9
  28. data/lib/reek/report/base_report.rb +77 -0
  29. data/lib/reek/report/code_climate.rb +4 -0
  30. data/lib/reek/report/code_climate/code_climate_fingerprint.rb +48 -0
  31. data/lib/reek/report/code_climate/code_climate_formatter.rb +5 -0
  32. data/lib/reek/report/code_climate/code_climate_report.rb +19 -0
  33. data/lib/reek/report/formatter.rb +5 -56
  34. data/lib/reek/report/{heading_formatter.rb → formatter/heading_formatter.rb} +4 -4
  35. data/lib/reek/report/formatter/location_formatter.rb +41 -0
  36. data/lib/reek/report/formatter/progress_formatter.rb +80 -0
  37. data/lib/reek/report/formatter/simple_warning_formatter.rb +35 -0
  38. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +35 -0
  39. data/lib/reek/report/html_report.rb +21 -0
  40. data/lib/reek/report/{html_report.html.erb → html_report/html_report.html.erb} +0 -0
  41. data/lib/reek/report/json_report.rb +18 -0
  42. data/lib/reek/report/text_report.rb +68 -0
  43. data/lib/reek/report/xml_report.rb +61 -0
  44. data/lib/reek/report/yaml_report.rb +18 -0
  45. data/lib/reek/smell_detectors.rb +30 -0
  46. data/lib/reek/{smells → smell_detectors}/attribute.rb +3 -3
  47. data/lib/reek/{smells/smell_detector.rb → smell_detectors/base_detector.rb} +3 -3
  48. data/lib/reek/{smells → smell_detectors}/boolean_parameter.rb +3 -3
  49. data/lib/reek/{smells → smell_detectors}/class_variable.rb +3 -3
  50. data/lib/reek/{smells → smell_detectors}/control_parameter.rb +3 -3
  51. data/lib/reek/{smells → smell_detectors}/data_clump.rb +3 -3
  52. data/lib/reek/{smells/smell_repository.rb → smell_detectors/detector_repository.rb} +9 -9
  53. data/lib/reek/{smells → smell_detectors}/duplicate_method_call.rb +3 -3
  54. data/lib/reek/{smells → smell_detectors}/feature_envy.rb +3 -3
  55. data/lib/reek/{smells → smell_detectors}/instance_variable_assumption.rb +3 -3
  56. data/lib/reek/{smells → smell_detectors}/irresponsible_module.rb +3 -3
  57. data/lib/reek/{smells → smell_detectors}/long_parameter_list.rb +3 -3
  58. data/lib/reek/{smells → smell_detectors}/long_yield_list.rb +3 -3
  59. data/lib/reek/{smells → smell_detectors}/manual_dispatch.rb +3 -3
  60. data/lib/reek/{smells → smell_detectors}/module_initialize.rb +3 -3
  61. data/lib/reek/{smells → smell_detectors}/nested_iterators.rb +3 -3
  62. data/lib/reek/{smells → smell_detectors}/nil_check.rb +3 -3
  63. data/lib/reek/{smells → smell_detectors}/prima_donna_method.rb +3 -3
  64. data/lib/reek/{smells → smell_detectors}/repeated_conditional.rb +3 -3
  65. data/lib/reek/{smells → smell_detectors}/smell_configuration.rb +1 -1
  66. data/lib/reek/{smells → smell_detectors}/smell_warning.rb +1 -1
  67. data/lib/reek/{smells → smell_detectors}/subclassed_from_core_class.rb +3 -3
  68. data/lib/reek/{smells → smell_detectors}/too_many_constants.rb +3 -3
  69. data/lib/reek/{smells → smell_detectors}/too_many_instance_variables.rb +3 -3
  70. data/lib/reek/{smells → smell_detectors}/too_many_methods.rb +3 -3
  71. data/lib/reek/{smells → smell_detectors}/too_many_statements.rb +3 -3
  72. data/lib/reek/{smells → smell_detectors}/uncommunicative_method_name.rb +3 -3
  73. data/lib/reek/{smells → smell_detectors}/uncommunicative_module_name.rb +3 -3
  74. data/lib/reek/{smells → smell_detectors}/uncommunicative_parameter_name.rb +3 -3
  75. data/lib/reek/{smells → smell_detectors}/uncommunicative_variable_name.rb +3 -3
  76. data/lib/reek/{smells → smell_detectors}/unused_parameters.rb +3 -3
  77. data/lib/reek/{smells → smell_detectors}/unused_private_method.rb +3 -3
  78. data/lib/reek/{smells → smell_detectors}/utility_function.rb +3 -3
  79. data/lib/reek/spec/should_reek_of.rb +1 -1
  80. data/lib/reek/version.rb +1 -1
  81. data/reek.gemspec +1 -1
  82. data/spec/factories/factories.rb +6 -6
  83. data/spec/reek/cli/command/report_command_spec.rb +3 -1
  84. data/spec/reek/cli/options_spec.rb +12 -2
  85. data/spec/reek/code_comment_spec.rb +18 -6
  86. data/spec/reek/configuration/app_configuration_spec.rb +12 -12
  87. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  88. data/spec/reek/configuration/directory_directives_spec.rb +2 -2
  89. data/spec/reek/examiner_spec.rb +56 -28
  90. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +122 -0
  91. data/spec/reek/report/{code_climate_formatter_spec.rb → code_climate/code_climate_formatter_spec.rb} +6 -2
  92. data/spec/reek/report/{code_climate_report_spec.rb → code_climate/code_climate_report_spec.rb} +7 -5
  93. data/spec/reek/report/{location_formatter_spec.rb → formatter/location_formatter_spec.rb} +4 -4
  94. data/spec/reek/report/formatter/progress_formatter_spec.rb +68 -0
  95. data/spec/reek/report/html_report_spec.rb +1 -1
  96. data/spec/reek/report/json_report_spec.rb +2 -2
  97. data/spec/reek/report/text_report_spec.rb +3 -4
  98. data/spec/reek/report/xml_report_spec.rb +1 -1
  99. data/spec/reek/report/yaml_report_spec.rb +2 -2
  100. data/spec/reek/report_spec.rb +3 -3
  101. data/spec/reek/{smells → smell_detectors}/attribute_spec.rb +2 -2
  102. data/spec/reek/{smells/smell_detector_spec.rb → smell_detectors/base_detector_spec.rb} +5 -5
  103. data/spec/reek/{smells → smell_detectors}/boolean_parameter_spec.rb +2 -2
  104. data/spec/reek/{smells → smell_detectors}/class_variable_spec.rb +2 -2
  105. data/spec/reek/{smells → smell_detectors}/control_parameter_spec.rb +2 -2
  106. data/spec/reek/{smells → smell_detectors}/data_clump_spec.rb +2 -2
  107. data/spec/reek/smell_detectors/detector_repository_spec.rb +22 -0
  108. data/spec/reek/{smells → smell_detectors}/duplicate_method_call_spec.rb +6 -6
  109. data/spec/reek/{smells → smell_detectors}/feature_envy_spec.rb +2 -2
  110. data/spec/reek/{smells → smell_detectors}/instance_variable_assumption_spec.rb +2 -2
  111. data/spec/reek/{smells → smell_detectors}/irresponsible_module_spec.rb +2 -2
  112. data/spec/reek/{smells → smell_detectors}/long_parameter_list_spec.rb +2 -2
  113. data/spec/reek/{smells → smell_detectors}/long_yield_list_spec.rb +2 -2
  114. data/spec/reek/{smells → smell_detectors}/manual_dispatch_spec.rb +2 -2
  115. data/spec/reek/{smells → smell_detectors}/module_initialize_spec.rb +2 -2
  116. data/spec/reek/{smells → smell_detectors}/nested_iterators_spec.rb +4 -4
  117. data/spec/reek/{smells → smell_detectors}/nil_check_spec.rb +2 -2
  118. data/spec/reek/{smells → smell_detectors}/prima_donna_method_spec.rb +2 -2
  119. data/spec/reek/{smells → smell_detectors}/repeated_conditional_spec.rb +2 -2
  120. data/spec/reek/{smells → smell_detectors}/smell_configuration_spec.rb +2 -2
  121. data/spec/reek/{smells → smell_detectors}/smell_warning_spec.rb +3 -3
  122. data/spec/reek/{smells → smell_detectors}/subclassed_from_core_class_spec.rb +2 -2
  123. data/spec/reek/{smells → smell_detectors}/too_many_constants_spec.rb +3 -3
  124. data/spec/reek/{smells → smell_detectors}/too_many_instance_variables_spec.rb +3 -3
  125. data/spec/reek/{smells → smell_detectors}/too_many_methods_spec.rb +3 -3
  126. data/spec/reek/{smells → smell_detectors}/too_many_statements_spec.rb +3 -3
  127. data/spec/reek/{smells → smell_detectors}/uncommunicative_method_name_spec.rb +2 -2
  128. data/spec/reek/{smells → smell_detectors}/uncommunicative_module_name_spec.rb +2 -2
  129. data/spec/reek/{smells → smell_detectors}/uncommunicative_parameter_name_spec.rb +2 -2
  130. data/spec/reek/{smells → smell_detectors}/uncommunicative_variable_name_spec.rb +2 -2
  131. data/spec/reek/{smells → smell_detectors}/unused_parameters_spec.rb +2 -2
  132. data/spec/reek/{smells → smell_detectors}/unused_private_method_spec.rb +4 -4
  133. data/spec/reek/{smells → smell_detectors}/utility_function_spec.rb +3 -3
  134. data/spec/reek/spec/should_reek_of_spec.rb +3 -3
  135. data/tasks/configuration.rake +2 -2
  136. metadata +95 -81
  137. data/features/smells/subclassed_from_core_class.feature +0 -14
  138. data/features/smells/too_many_constants.feature +0 -19
  139. data/lib/reek/errors.rb +0 -32
  140. data/lib/reek/report/location_formatter.rb +0 -39
  141. data/lib/reek/report/report.rb +0 -229
  142. data/lib/reek/smells.rb +0 -30
  143. data/spec/reek/smells/smell_repository_spec.rb +0 -22
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'smell_detector'
2
+ require_relative 'base_detector'
3
3
  require_relative 'smell_warning'
4
4
 
5
5
  module Reek
6
- module Smells
6
+ module SmellDetectors
7
7
  #
8
8
  # Methods should use their parameters.
9
9
  #
10
10
  # See {file:docs/Unused-Parameters.md} for details.
11
- class UnusedParameters < SmellDetector
11
+ class UnusedParameters < BaseDetector
12
12
  #
13
13
  # Checks whether the given method has any unused parameters.
14
14
  #
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'smell_detector'
2
+ require_relative 'base_detector'
3
3
  require_relative 'smell_warning'
4
4
  require_relative '../context/method_context'
5
5
 
6
6
  module Reek
7
- module Smells
7
+ module SmellDetectors
8
8
  #
9
9
  # Classes should use their private methods. Otherwise this is dead
10
10
  # code which is confusing and bad for maintenance.
11
11
  #
12
12
  # See {file:docs/Unused-Private-Method.md} for details.
13
13
  #
14
- class UnusedPrivateMethod < SmellDetector
14
+ class UnusedPrivateMethod < BaseDetector
15
15
  def self.default_config
16
16
  super.merge(SmellConfiguration::ENABLED_KEY => false)
17
17
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative '../ast/reference_collector'
3
- require_relative 'smell_detector'
3
+ require_relative 'base_detector'
4
4
  require_relative 'smell_warning'
5
5
 
6
6
  module Reek
7
- module Smells
7
+ module SmellDetectors
8
8
  #
9
9
  # A Utility Function is any instance method that has no
10
10
  # dependency on the state of the instance.
@@ -37,7 +37,7 @@ module Reek
37
37
  # +FeatureEnvy+ is reported instead.
38
38
  #
39
39
  # See {file:docs/Utility-Function.md} for details.
40
- class UtilityFunction < SmellDetector
40
+ class UtilityFunction < BaseDetector
41
41
  PUBLIC_METHODS_ONLY_KEY = 'public_methods_only'.freeze
42
42
  PUBLIC_METHODS_ONLY_DEFAULT = false
43
43
 
@@ -25,7 +25,7 @@ module Reek
25
25
  configuration = Configuration::AppConfiguration.default)
26
26
  @smell_type = normalize smell_type_or_class
27
27
  @smell_details = smell_details
28
- configuration.load_values(smell_type => { Smells::SmellConfiguration::ENABLED_KEY => true })
28
+ configuration.load_values(smell_type => { SmellDetectors::SmellConfiguration::ENABLED_KEY => true })
29
29
  @configuration = configuration
30
30
  end
31
31
 
@@ -7,6 +7,6 @@ module Reek
7
7
  # @public
8
8
  module Version
9
9
  # @public
10
- STRING = '4.4.2'.freeze
10
+ STRING = '4.5.0'.freeze
11
11
  end
12
12
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.required_ruby_version = '>= 2.1.0'
22
22
  s.summary = 'Code smell detector for Ruby'
23
23
 
24
- s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.3.1'
24
+ s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.4.0'
25
25
  s.add_runtime_dependency 'parser', '~> 2.3.1', '>= 2.3.1.2'
26
26
  s.add_runtime_dependency 'rainbow', '~> 2.0'
27
27
  end
@@ -1,6 +1,6 @@
1
- require_relative '../../lib/reek/smells'
2
- require_relative '../../lib/reek/smells/smell_detector'
3
- require_relative '../../lib/reek/smells/smell_warning'
1
+ require_relative '../../lib/reek/smell_detectors'
2
+ require_relative '../../lib/reek/smell_detectors/base_detector'
3
+ require_relative '../../lib/reek/smell_detectors/smell_warning'
4
4
  require_relative '../../lib/reek/cli/options'
5
5
 
6
6
  FactoryGirl.define do
@@ -23,18 +23,18 @@ FactoryGirl.define do
23
23
  end
24
24
  end
25
25
 
26
- factory :smell_detector, class: Reek::Smells::SmellDetector do
26
+ factory :smell_detector, class: Reek::SmellDetectors::BaseDetector do
27
27
  skip_create
28
28
  transient do
29
29
  smell_type 'FeatureEnvy'
30
30
  end
31
31
 
32
32
  initialize_with do
33
- ::Reek::Smells.const_get(smell_type).new
33
+ ::Reek::SmellDetectors.const_get(smell_type).new
34
34
  end
35
35
  end
36
36
 
37
- factory :smell_warning, class: Reek::Smells::SmellWarning do
37
+ factory :smell_warning, class: Reek::SmellDetectors::SmellWarning do
38
38
  skip_create
39
39
  smell_detector
40
40
  context 'self'
@@ -23,7 +23,9 @@ RSpec.describe Reek::CLI::Command::ReportCommand do
23
23
  let(:source_file) { CLEAN_FILE }
24
24
 
25
25
  it 'returns a success code' do
26
- result = command.execute
26
+ result = Reek::CLI::Silencer.silently do
27
+ command.execute
28
+ end
27
29
  expect(result).to eq Reek::CLI::Options::DEFAULT_SUCCESS_EXIT_CODE
28
30
  end
29
31
  end
@@ -14,13 +14,23 @@ RSpec.describe Reek::CLI::Options do
14
14
  end
15
15
 
16
16
  it 'enables colors when stdout is a TTY' do
17
+ allow($stdout).to receive_messages(tty?: true)
18
+ expect(options.colored).to be true
19
+ end
20
+
21
+ it 'does not enable colors when stdout is not a TTY' do
17
22
  allow($stdout).to receive_messages(tty?: false)
18
23
  expect(options.colored).to be false
19
24
  end
20
25
 
21
- it 'does not enable colors when stdout is not a TTY' do
26
+ it 'enables progress when stdout is a TTY' do
22
27
  allow($stdout).to receive_messages(tty?: true)
23
- expect(options.colored).to be true
28
+ expect(options.progress_format).to eq :dots
29
+ end
30
+
31
+ it 'does not enable progress when stdout is not a TTY' do
32
+ allow($stdout).to receive_messages(tty?: false)
33
+ expect(options.progress_format).to eq :quiet
24
34
  end
25
35
  end
26
36
 
@@ -1,6 +1,5 @@
1
1
  require_relative '../spec_helper'
2
2
  require_lib 'reek/code_comment'
3
- require_lib 'reek/errors'
4
3
 
5
4
  RSpec.describe Reek::CodeComment do
6
5
  context 'with an empty comment' do
@@ -123,11 +122,24 @@ RSpec.describe Reek::CodeComment do
123
122
  expect(comment.send(:sanitized_comment)).to eq('Actual comment')
124
123
  end
125
124
  end
125
+ end
126
126
 
127
- it 'raises BadConfigurationError on bad comment config' do
128
- expect do
129
- FactoryGirl.build(:code_comment,
130
- comment: '# :reek:DoesNotExist')
131
- end.to raise_error(Reek::BadDetectorInCommentError)
127
+ RSpec.describe Reek::CodeComment::CodeCommentValidator do
128
+ context 'bad detector' do
129
+ it 'raises BadDetectorInCommentError' do
130
+ expect do
131
+ FactoryGirl.build(:code_comment,
132
+ comment: '# :reek:DoesNotExist')
133
+ end.to raise_error(Reek::Errors::BadDetectorInCommentError)
134
+ end
135
+ end
136
+
137
+ context 'unparsable detector configuration' do
138
+ it 'raises GarbageDetectorConfigurationInCommentError' do
139
+ expect do
140
+ comment = '# :reek:UncommunicativeMethodName { thats: a: bad: config }'
141
+ FactoryGirl.build(:code_comment, comment: comment)
142
+ end.to raise_error(Reek::Errors::GarbageDetectorConfigurationInCommentError)
143
+ end
132
144
  end
133
145
  end
@@ -13,12 +13,12 @@ RSpec.describe Reek::Configuration::AppConfiguration do
13
13
  end
14
14
 
15
15
  let(:expected_default_directive) do
16
- { Reek::Smells::IrresponsibleModule => { 'enabled' => false } }
16
+ { Reek::SmellDetectors::IrresponsibleModule => { 'enabled' => false } }
17
17
  end
18
18
 
19
19
  let(:expected_directory_directives) do
20
20
  { SAMPLES_PATH.join('three_clean_files') =>
21
- { Reek::Smells::UtilityFunction => { 'enabled' => false } } }
21
+ { Reek::SmellDetectors::UtilityFunction => { 'enabled' => false } } }
22
22
  end
23
23
 
24
24
  let(:default_directive_value) do
@@ -77,8 +77,8 @@ RSpec.describe Reek::Configuration::AppConfiguration do
77
77
  describe '#directive_for' do
78
78
  context 'multiple directory directives and no default directive present' do
79
79
  let(:source_via) { 'samples/three_clean_files/dummy.rb' }
80
- let(:baz_config) { { Reek::Smells::IrresponsibleModule => { enabled: false } } }
81
- let(:bang_config) { { Reek::Smells::Attribute => { enabled: true } } }
80
+ let(:baz_config) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
81
+ let(:bang_config) { { Reek::SmellDetectors::Attribute => { enabled: true } } }
82
82
 
83
83
  let(:directory_directives) do
84
84
  {
@@ -95,12 +95,12 @@ RSpec.describe Reek::Configuration::AppConfiguration do
95
95
 
96
96
  context 'directory directive and default directive present' do
97
97
  let(:directory) { 'spec/samples/two_smelly_files/' }
98
- let(:directory_config) { { Reek::Smells::TooManyStatements => { max_statements: 8 } } }
98
+ let(:directory_config) { { Reek::SmellDetectors::TooManyStatements => { max_statements: 8 } } }
99
99
  let(:directory_directives) { { directory => directory_config } }
100
100
  let(:default_directive) do
101
101
  {
102
- Reek::Smells::IrresponsibleModule => { enabled: false },
103
- Reek::Smells::TooManyStatements => { max_statements: 15 }
102
+ Reek::SmellDetectors::IrresponsibleModule => { enabled: false },
103
+ Reek::SmellDetectors::TooManyStatements => { max_statements: 15 }
104
104
  }
105
105
  end
106
106
  let(:source_via) { "#{directory}/dummy.rb" }
@@ -110,16 +110,16 @@ RSpec.describe Reek::Configuration::AppConfiguration do
110
110
  configuration = described_class.from_hash configuration_as_hash
111
111
  actual = configuration.directive_for(source_via)
112
112
 
113
- expect(actual[Reek::Smells::IrresponsibleModule]).to be_truthy
114
- expect(actual[Reek::Smells::TooManyStatements]).to be_truthy
115
- expect(actual[Reek::Smells::TooManyStatements][:max_statements]).to eq(8)
113
+ expect(actual[Reek::SmellDetectors::IrresponsibleModule]).to be_truthy
114
+ expect(actual[Reek::SmellDetectors::TooManyStatements]).to be_truthy
115
+ expect(actual[Reek::SmellDetectors::TooManyStatements][:max_statements]).to eq(8)
116
116
  end
117
117
  end
118
118
 
119
119
  context 'no directory directive but a default directive present' do
120
120
  let(:source_via) { 'spec/samples/three_clean_files/dummy.rb' }
121
- let(:default_directive) { { Reek::Smells::IrresponsibleModule => { enabled: false } } }
122
- let(:attribute_config) { { Reek::Smells::Attribute => { enabled: false } } }
121
+ let(:default_directive) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
122
+ let(:attribute_config) { { Reek::SmellDetectors::Attribute => { enabled: false } } }
123
123
  let(:directory_directives) do
124
124
  { 'spec/samples/two_smelly_files' => attribute_config }
125
125
  end
@@ -7,7 +7,7 @@ RSpec.describe Reek::Configuration::DefaultDirective do
7
7
 
8
8
  it 'adds a smell configuration' do
9
9
  directives.add :UncommunicativeVariableName, enabled: false
10
- expect(directives).to eq(Reek::Smells::UncommunicativeVariableName => { enabled: false })
10
+ expect(directives).to eq(Reek::SmellDetectors::UncommunicativeVariableName => { enabled: false })
11
11
  end
12
12
  end
13
13
  end
@@ -3,8 +3,8 @@ require_lib 'reek/configuration/directory_directives'
3
3
 
4
4
  RSpec.describe Reek::Configuration::DirectoryDirectives do
5
5
  describe '#directive_for' do
6
- let(:baz_config) { { Reek::Smells::IrresponsibleModule => { enabled: false } } }
7
- let(:bang_config) { { Reek::Smells::Attribute => { enabled: true } } }
6
+ let(:baz_config) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
7
+ let(:bang_config) { { Reek::SmellDetectors::Attribute => { enabled: true } } }
8
8
  let(:directives) do
9
9
  {
10
10
  Pathname.new('foo/bar/baz') => baz_config,
@@ -87,7 +87,7 @@ RSpec.describe Reek::Examiner do
87
87
  examiner = described_class.new code, filter_by_smells: ['DuplicateMethodCall']
88
88
 
89
89
  smell = examiner.smells.first
90
- expect(smell).to be_a(Reek::Smells::SmellWarning)
90
+ expect(smell).to be_a(Reek::SmellDetectors::SmellWarning)
91
91
  expect(smell.message).to eq("calls 'bar.call_me()' 2 times")
92
92
  end
93
93
 
@@ -111,13 +111,13 @@ RSpec.describe Reek::Examiner do
111
111
  let(:source) { 'class C; def does_crash_reek; end; end' }
112
112
 
113
113
  let(:examiner) do
114
- smell_repository = instance_double 'Reek::Smells::SmellRepository'
115
- allow(smell_repository).to receive(:examine) do
114
+ detector_repository = instance_double 'Reek::SmellDetectors::DetectorRepository'
115
+ allow(detector_repository).to receive(:examine) do
116
116
  raise ArgumentError, 'Looks like bad source'
117
117
  end
118
- class_double('Reek::Smells::SmellRepository').as_stubbed_const
119
- allow(Reek::Smells::SmellRepository).to receive(:eligible_smell_types)
120
- allow(Reek::Smells::SmellRepository).to receive(:new).and_return smell_repository
118
+ class_double('Reek::SmellDetectors::DetectorRepository').as_stubbed_const
119
+ allow(Reek::SmellDetectors::DetectorRepository).to receive(:eligible_smell_types)
120
+ allow(Reek::SmellDetectors::DetectorRepository).to receive(:new).and_return detector_repository
121
121
 
122
122
  described_class.new source
123
123
  end
@@ -128,46 +128,74 @@ RSpec.describe Reek::Examiner do
128
128
  end
129
129
  end
130
130
 
131
- it 'outputs the origin to STDERR' do
131
+ it 'prints the origin' do
132
132
  origin = 'string'
133
133
  expect { examiner.smells }.to output(/#{origin}/).to_stderr
134
134
  end
135
135
 
136
- it 'explains what to do to STDERR' do
137
- explanation = 'It would be great if you could report this back to the Reek team'
136
+ it 'explains what to do' do
137
+ explanation = 'Please double check your Reek configuration'
138
138
  expect { examiner.smells }.to output(/#{explanation}/).to_stderr
139
139
  end
140
140
 
141
- it 'outputs the original exception to STDERR' do
142
- original = '#<ArgumentError: Looks like bad source>'
141
+ it 'contains a message' do
142
+ original = 'Looks like bad source'
143
143
  expect { examiner.smells }.to output(/#{original}/).to_stderr
144
144
  end
145
145
  end
146
146
  end
147
147
 
148
148
  describe 'bad comment config' do
149
- let(:source) do
150
- <<-EOS
151
- # :reek:DoesNotExist
152
- def alfa; end
153
- EOS
154
- end
149
+ context 'unknown smell detector' do
150
+ let(:source) do
151
+ <<-EOS
152
+ # :reek:DoesNotExist
153
+ def alfa; end
154
+ EOS
155
+ end
155
156
 
156
- it 'prints out a proper message' do
157
- expected_output = "You are trying to configure an unknown smell detector 'DoesNotExist'"
157
+ it 'prints out a proper message' do
158
+ expected_output = "You are trying to configure an unknown smell detector 'DoesNotExist'"
158
159
 
159
- expect do
160
- described_class.new(source).smells
161
- end.to output(/#{expected_output}/).to_stderr
160
+ expect do
161
+ described_class.new(source).smells
162
+ end.to output(/#{expected_output}/).to_stderr
163
+ end
164
+
165
+ it 'prints out a line and a source' do
166
+ expected_output = "The source is 'string' and the comment belongs "\
167
+ 'to the expression starting in line 2.'
168
+
169
+ expect do
170
+ described_class.new(source).smells
171
+ end.to output(/#{expected_output}/).to_stderr
172
+ end
162
173
  end
163
174
 
164
- it 'prints out a line and a source' do
165
- expected_output = "The source is 'string' and the comment belongs "\
166
- 'to the expression starting in line 2.'
175
+ context 'garbage in detector config' do
176
+ let(:source) do
177
+ <<-EOS
178
+ # :reek:UncommunicativeMethodName { thats: a: bad: config }
179
+ def alfa; end
180
+ EOS
181
+ end
182
+
183
+ it 'prints out a proper message' do
184
+ expected_output = "Error: You are trying to configure the smell detector 'UncommunicativeMethodName'"
167
185
 
168
- expect do
169
- described_class.new(source).smells
170
- end.to output(/#{expected_output}/).to_stderr
186
+ expect do
187
+ described_class.new(source).smells
188
+ end.to output(/#{expected_output}/).to_stderr
189
+ end
190
+
191
+ it 'prints out a line and a source' do
192
+ expected_output = "The source is 'string' and "\
193
+ 'the comment belongs to the expression starting in line 2'
194
+
195
+ expect do
196
+ described_class.new(source).smells
197
+ end.to output(/#{expected_output}/).to_stderr
198
+ end
171
199
  end
172
200
  end
173
201
  end
@@ -0,0 +1,122 @@
1
+ require_relative '../../../spec_helper'
2
+ require_lib 'reek/report/code_climate/code_climate_fingerprint'
3
+
4
+ RSpec.describe Reek::Report::CodeClimateFingerprint do
5
+ describe '#compute' do
6
+ let(:computed) { described_class.new(warning).compute }
7
+
8
+ shared_examples_for 'computes a fingerprint with no parameters' do
9
+ let(:expected_fingerprint) { 'e68badd29db51c92363a7c6a2438d722' }
10
+ let(:warning) do
11
+ FactoryGirl.build(:smell_warning,
12
+ smell_detector: Reek::SmellDetectors::UtilityFunction.new,
13
+ context: 'alfa',
14
+ message: "doesn't depend on instance state (maybe move it to another class?)",
15
+ lines: lines,
16
+ source: 'a/ruby/source/file.rb')
17
+ end
18
+
19
+ it 'it computes the fingerprint' do
20
+ expect(computed).to eq expected_fingerprint
21
+ end
22
+ end
23
+
24
+ context 'with code at a specific location' do
25
+ let(:lines) { [1] }
26
+ it_should_behave_like 'computes a fingerprint with no parameters'
27
+ end
28
+
29
+ context 'with code at a different location' do
30
+ let(:lines) { [5] }
31
+ it_should_behave_like 'computes a fingerprint with no parameters'
32
+ end
33
+
34
+ context 'when the fingerprint should not be computed' do
35
+ let(:warning) do
36
+ FactoryGirl.build(:smell_warning,
37
+ smell_detector: Reek::SmellDetectors::ManualDispatch.new,
38
+ context: 'Alfa#bravo',
39
+ message: 'manually dispatches method call',
40
+ lines: [4],
41
+ source: 'a/ruby/source/file.rb')
42
+ end
43
+
44
+ it 'it returns nil' do
45
+ expect(computed).to be_nil
46
+ end
47
+ end
48
+
49
+ shared_examples_for 'computes a fingerprint with identifying parameters' do
50
+ let(:warning) do
51
+ FactoryGirl.build(:smell_warning,
52
+ smell_detector: Reek::SmellDetectors::ClassVariable.new,
53
+ context: 'Alfa',
54
+ message: "declares the class variable '@@#{name}'",
55
+ lines: [4],
56
+ parameters: { name: "@@#{name}" },
57
+ source: 'a/ruby/source/file.rb')
58
+ end
59
+
60
+ it 'computes the fingerprint' do
61
+ expect(computed).to eq expected_fingerprint
62
+ end
63
+ end
64
+
65
+ context 'when the name is one thing it has one fingerprint' do
66
+ let(:name) { 'bravo' }
67
+ let(:expected_fingerprint) { '9c3fd378178118a67e9509f87cae24f9' }
68
+
69
+ it_should_behave_like 'computes a fingerprint with identifying parameters'
70
+ end
71
+
72
+ context 'when the name is another thing it has another fingerprint' do
73
+ let(:name) { 'echo' }
74
+ let(:expected_fingerprint) { 'd2a6d2703ce04cca65e7300b7de4b89f' }
75
+
76
+ it_should_behave_like 'computes a fingerprint with identifying parameters'
77
+ end
78
+
79
+ shared_examples_for 'computes a fingerprint with identifying and non-identifying parameters' do
80
+ let(:warning) do
81
+ FactoryGirl.build(:smell_warning,
82
+ smell_detector: Reek::SmellDetectors::DuplicateMethodCall.new,
83
+ context: "Alfa##{name}",
84
+ message: "calls '#{name}' #{count} times",
85
+ lines: lines,
86
+ parameters: { name: "@@#{name}", count: count },
87
+ source: 'a/ruby/source/file.rb')
88
+ end
89
+
90
+ it 'computes the fingerprint' do
91
+ expect(computed).to eq expected_fingerprint
92
+ end
93
+ end
94
+
95
+ context 'when the parameters are provided' do
96
+ let(:name) { 'bravo' }
97
+ let(:count) { 5 }
98
+ let(:lines) { [1, 7, 10, 13, 15] }
99
+ let(:expected_fingerprint) { '238733f4f51ba5473dcbe94a43ec5400' }
100
+
101
+ it_should_behave_like 'computes a fingerprint with identifying and non-identifying parameters'
102
+ end
103
+
104
+ context 'when the non-identifying parameters change, it computes the same fingerprint' do
105
+ let(:name) { 'bravo' }
106
+ let(:count) { 9 }
107
+ let(:lines) { [1, 7, 10, 13, 15, 17, 19, 20, 25] }
108
+ let(:expected_fingerprint) { '238733f4f51ba5473dcbe94a43ec5400' }
109
+
110
+ it_should_behave_like 'computes a fingerprint with identifying and non-identifying parameters'
111
+ end
112
+
113
+ context 'but when the identifying parameters change, it computes a different fingerprint' do
114
+ let(:name) { 'echo' }
115
+ let(:count) { 5 }
116
+ let(:lines) { [1, 7, 10, 13, 15] }
117
+ let(:expected_fingerprint) { 'e0c35e9223cc19bdb9a04fb3e60573e1' }
118
+
119
+ it_should_behave_like 'computes a fingerprint with identifying and non-identifying parameters'
120
+ end
121
+ end
122
+ end