reek 1.2.6 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. data/.yardopts +10 -0
  2. data/History.txt +62 -0
  3. data/README.md +74 -0
  4. data/bin/reek +2 -2
  5. data/config/defaults.reek +44 -5
  6. data/features/api.feature +20 -0
  7. data/features/masking_smells.feature +60 -42
  8. data/features/options.feature +7 -2
  9. data/features/rake_task.feature +29 -22
  10. data/features/reports.feature +9 -41
  11. data/features/samples.feature +184 -196
  12. data/features/stdin.feature +5 -8
  13. data/features/step_definitions/reek_steps.rb +8 -4
  14. data/features/support/env.rb +2 -3
  15. data/features/yaml.feature +85 -0
  16. data/lib/reek/cli/application.rb +46 -0
  17. data/lib/reek/cli/command_line.rb +108 -0
  18. data/lib/reek/cli/help_command.rb +18 -0
  19. data/lib/reek/cli/reek_command.rb +37 -0
  20. data/lib/reek/cli/report.rb +58 -0
  21. data/lib/reek/cli/version_command.rb +19 -0
  22. data/lib/reek/cli/yaml_command.rb +32 -0
  23. data/lib/reek/core/code_context.rb +64 -0
  24. data/lib/reek/core/code_parser.rb +166 -0
  25. data/lib/reek/core/method_context.rb +84 -0
  26. data/lib/reek/core/module_context.rb +20 -0
  27. data/lib/reek/core/object_refs.rb +51 -0
  28. data/lib/reek/core/singleton_method_context.rb +20 -0
  29. data/lib/reek/core/smell_configuration.rb +62 -0
  30. data/lib/reek/core/sniffer.rb +105 -0
  31. data/lib/reek/core/stop_context.rb +30 -0
  32. data/lib/reek/core/warning_collector.rb +27 -0
  33. data/lib/reek/examiner.rb +104 -0
  34. data/lib/reek/rake/task.rb +142 -0
  35. data/lib/reek/smell_warning.rb +73 -23
  36. data/lib/reek/smells/attribute.rb +26 -21
  37. data/lib/reek/smells/boolean_parameter.rb +38 -0
  38. data/lib/reek/smells/class_variable.rb +22 -9
  39. data/lib/reek/smells/control_couple.rb +40 -16
  40. data/lib/reek/smells/data_clump.rb +114 -23
  41. data/lib/reek/smells/duplication.rb +55 -15
  42. data/lib/reek/smells/feature_envy.rb +16 -7
  43. data/lib/reek/smells/irresponsible_module.rb +37 -0
  44. data/lib/reek/smells/large_class.rb +37 -19
  45. data/lib/reek/smells/long_method.rb +20 -9
  46. data/lib/reek/smells/long_parameter_list.rb +22 -10
  47. data/lib/reek/smells/long_yield_list.rb +43 -7
  48. data/lib/reek/smells/nested_iterators.rb +68 -8
  49. data/lib/reek/smells/simulated_polymorphism.rb +26 -15
  50. data/lib/reek/smells/smell_detector.rb +29 -51
  51. data/lib/reek/smells/uncommunicative_method_name.rb +74 -0
  52. data/lib/reek/smells/uncommunicative_module_name.rb +74 -0
  53. data/lib/reek/smells/uncommunicative_parameter_name.rb +79 -0
  54. data/lib/reek/smells/uncommunicative_variable_name.rb +89 -0
  55. data/lib/reek/smells/utility_function.rb +51 -12
  56. data/lib/reek/smells.rb +29 -0
  57. data/lib/reek/source/code_comment.rb +37 -0
  58. data/lib/reek/source/config_file.rb +72 -0
  59. data/lib/reek/source/core_extras.rb +46 -0
  60. data/lib/reek/source/reference_collector.rb +28 -0
  61. data/lib/reek/source/sexp_formatter.rb +17 -0
  62. data/lib/reek/source/source_code.rb +44 -0
  63. data/lib/reek/source/source_file.rb +32 -0
  64. data/lib/reek/source/source_locator.rb +42 -0
  65. data/lib/reek/source/tree_dresser.rb +204 -0
  66. data/lib/reek/source.rb +18 -0
  67. data/lib/reek/spec/should_reek.rb +31 -0
  68. data/lib/reek/spec/should_reek_of.rb +37 -0
  69. data/lib/reek/spec/should_reek_only_of.rb +37 -0
  70. data/lib/reek/spec.rb +51 -0
  71. data/lib/reek.rb +8 -4
  72. data/reek.gemspec +9 -7
  73. data/spec/matchers/smell_of_matcher.rb +58 -0
  74. data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
  75. data/spec/reek/cli/reek_command_spec.rb +46 -0
  76. data/spec/reek/cli/report_spec.rb +30 -0
  77. data/spec/reek/{version_command_spec.rb → cli/version_command_spec.rb} +3 -3
  78. data/spec/reek/cli/yaml_command_spec.rb +47 -0
  79. data/spec/reek/core/code_context_spec.rb +145 -0
  80. data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +7 -6
  81. data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
  82. data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +16 -36
  83. data/spec/reek/core/module_context_spec.rb +27 -0
  84. data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
  85. data/spec/reek/core/singleton_method_context_spec.rb +9 -0
  86. data/spec/reek/core/smell_configuration_spec.rb +11 -0
  87. data/spec/reek/core/stop_context_spec.rb +17 -0
  88. data/spec/reek/core/warning_collector_spec.rb +27 -0
  89. data/spec/reek/examiner_spec.rb +103 -0
  90. data/spec/reek/smell_warning_spec.rb +74 -82
  91. data/spec/reek/smells/attribute_spec.rb +42 -23
  92. data/spec/reek/smells/behaves_like_variable_detector.rb +2 -2
  93. data/spec/reek/smells/boolean_parameter_spec.rb +66 -0
  94. data/spec/reek/smells/class_variable_spec.rb +60 -75
  95. data/spec/reek/smells/control_couple_spec.rb +37 -32
  96. data/spec/reek/smells/data_clump_spec.rb +63 -24
  97. data/spec/reek/smells/duplication_spec.rb +106 -57
  98. data/spec/reek/smells/feature_envy_spec.rb +113 -92
  99. data/spec/reek/smells/irresponsible_module_spec.rb +58 -0
  100. data/spec/reek/smells/large_class_spec.rb +67 -57
  101. data/spec/reek/smells/long_method_spec.rb +40 -10
  102. data/spec/reek/smells/long_parameter_list_spec.rb +50 -28
  103. data/spec/reek/smells/long_yield_list_spec.rb +57 -0
  104. data/spec/reek/smells/nested_iterators_spec.rb +115 -7
  105. data/spec/reek/smells/simulated_polymorphism_spec.rb +56 -20
  106. data/spec/reek/smells/smell_detector_shared.rb +42 -0
  107. data/spec/reek/smells/uncommunicative_method_name_spec.rb +42 -0
  108. data/spec/reek/smells/uncommunicative_module_name_spec.rb +66 -0
  109. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +71 -0
  110. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +120 -0
  111. data/spec/reek/smells/utility_function_spec.rb +50 -4
  112. data/spec/reek/source/code_comment_spec.rb +82 -0
  113. data/spec/reek/source/object_source_spec.rb +20 -0
  114. data/spec/reek/source/reference_collector_spec.rb +53 -0
  115. data/spec/reek/{adapters/source_spec.rb → source/source_code_spec.rb} +7 -8
  116. data/spec/reek/source/tree_dresser_spec.rb +270 -0
  117. data/spec/reek/spec/should_reek_of_spec.rb +76 -0
  118. data/spec/reek/spec/should_reek_only_of_spec.rb +89 -0
  119. data/spec/reek/{adapters → spec}/should_reek_spec.rb +8 -32
  120. data/spec/samples/all_but_one_masked/clean_one.rb +1 -0
  121. data/spec/samples/all_but_one_masked/dirty.rb +1 -0
  122. data/spec/samples/all_but_one_masked/masked.reek +5 -1
  123. data/spec/samples/clean_due_to_masking/clean_one.rb +1 -0
  124. data/spec/samples/clean_due_to_masking/clean_three.rb +1 -0
  125. data/spec/samples/clean_due_to_masking/clean_two.rb +1 -0
  126. data/spec/samples/clean_due_to_masking/dirty_one.rb +1 -1
  127. data/spec/samples/clean_due_to_masking/dirty_two.rb +1 -1
  128. data/spec/samples/clean_due_to_masking/masked.reek +5 -1
  129. data/spec/samples/config/allow_duplication.reek +3 -0
  130. data/spec/samples/config/deeper_nested_iterators.reek +3 -0
  131. data/spec/samples/corrupt_config_file/dirty.rb +1 -1
  132. data/spec/samples/demo/demo.rb +8 -0
  133. data/spec/samples/empty_config_file/dirty.rb +2 -1
  134. data/spec/samples/exceptions.reek +1 -1
  135. data/spec/samples/inline_config/dirty.rb +16 -0
  136. data/spec/samples/inline_config/masked.reek +7 -0
  137. data/spec/samples/mask_some/dirty.rb +8 -0
  138. data/spec/samples/mask_some/some.reek +8 -0
  139. data/spec/samples/masked/dirty.rb +2 -1
  140. data/spec/samples/masked/masked.reek +3 -1
  141. data/spec/samples/mixed_results/clean_one.rb +1 -0
  142. data/spec/samples/mixed_results/clean_three.rb +1 -0
  143. data/spec/samples/mixed_results/clean_two.rb +1 -0
  144. data/spec/samples/mixed_results/dirty_one.rb +1 -0
  145. data/spec/samples/mixed_results/dirty_two.rb +1 -0
  146. data/spec/samples/not_quite_masked/dirty.rb +2 -1
  147. data/spec/samples/not_quite_masked/masked.reek +1 -1
  148. data/spec/samples/overrides/masked/dirty.rb +2 -1
  149. data/spec/samples/overrides/masked/lower.reek +3 -1
  150. data/spec/samples/three_clean_files/clean_one.rb +1 -0
  151. data/spec/samples/three_clean_files/clean_three.rb +1 -0
  152. data/spec/samples/three_clean_files/clean_two.rb +1 -0
  153. data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
  154. data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
  155. data/spec/spec_helper.rb +10 -2
  156. data/tasks/reek.rake +2 -2
  157. data/tasks/test.rake +12 -3
  158. metadata +121 -79
  159. data/README.rdoc +0 -84
  160. data/features/profile.feature +0 -34
  161. data/lib/reek/adapters/application.rb +0 -46
  162. data/lib/reek/adapters/command_line.rb +0 -77
  163. data/lib/reek/adapters/config_file.rb +0 -31
  164. data/lib/reek/adapters/core_extras.rb +0 -64
  165. data/lib/reek/adapters/rake_task.rb +0 -121
  166. data/lib/reek/adapters/report.rb +0 -86
  167. data/lib/reek/adapters/source.rb +0 -72
  168. data/lib/reek/adapters/spec.rb +0 -133
  169. data/lib/reek/block_context.rb +0 -62
  170. data/lib/reek/class_context.rb +0 -41
  171. data/lib/reek/code_context.rb +0 -68
  172. data/lib/reek/code_parser.rb +0 -203
  173. data/lib/reek/configuration.rb +0 -57
  174. data/lib/reek/detector_stack.rb +0 -37
  175. data/lib/reek/help_command.rb +0 -14
  176. data/lib/reek/if_context.rb +0 -18
  177. data/lib/reek/masking_collection.rb +0 -33
  178. data/lib/reek/method_context.rb +0 -138
  179. data/lib/reek/module_context.rb +0 -49
  180. data/lib/reek/name.rb +0 -57
  181. data/lib/reek/object_refs.rb +0 -49
  182. data/lib/reek/reek_command.rb +0 -28
  183. data/lib/reek/sexp_formatter.rb +0 -10
  184. data/lib/reek/singleton_method_context.rb +0 -26
  185. data/lib/reek/smells/uncommunicative_name.rb +0 -84
  186. data/lib/reek/sniffer.rb +0 -177
  187. data/lib/reek/stop_context.rb +0 -35
  188. data/lib/reek/tree_dresser.rb +0 -82
  189. data/lib/reek/version_command.rb +0 -14
  190. data/lib/reek/yield_call_context.rb +0 -12
  191. data/spec/reek/adapters/report_spec.rb +0 -31
  192. data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
  193. data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
  194. data/spec/reek/block_context_spec.rb +0 -65
  195. data/spec/reek/class_context_spec.rb +0 -161
  196. data/spec/reek/code_context_spec.rb +0 -182
  197. data/spec/reek/configuration_spec.rb +0 -12
  198. data/spec/reek/if_context_spec.rb +0 -17
  199. data/spec/reek/masking_collection_spec.rb +0 -236
  200. data/spec/reek/module_context_spec.rb +0 -46
  201. data/spec/reek/name_spec.rb +0 -37
  202. data/spec/reek/object_source_spec.rb +0 -23
  203. data/spec/reek/reek_command_spec.rb +0 -45
  204. data/spec/reek/singleton_method_context_spec.rb +0 -16
  205. data/spec/reek/smells/smell_detector_spec.rb +0 -36
  206. data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
  207. data/spec/reek/sniffer_spec.rb +0 -11
  208. data/spec/reek/stop_context_spec.rb +0 -33
  209. data/spec/reek/tree_dresser_spec.rb +0 -20
@@ -1,15 +1,19 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'simulated_polymorphism')
3
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'code_context')
4
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
2
5
 
3
- require 'reek/smells/simulated_polymorphism'
4
- require 'reek/code_context'
5
-
6
- include Reek
6
+ include Reek::Core
7
7
  include Reek::Smells
8
8
 
9
9
  describe SimulatedPolymorphism do
10
10
  before :each do
11
- @detector = SimulatedPolymorphism.new
11
+ @source_name = 'howdy-doody'
12
+ @detector = SimulatedPolymorphism.new(@source_name)
12
13
  end
14
+
15
+ it_should_behave_like 'SmellDetector'
16
+
13
17
  context 'with no conditionals' do
14
18
  it 'gathers an empty hash' do
15
19
  ast = 'module Stable; end'.to_reek_source.syntax_tree
@@ -26,38 +30,70 @@ describe SimulatedPolymorphism do
26
30
  end
27
31
  end
28
32
 
33
+ context 'with an empty condition' do
34
+ it 'does not record the condition' do
35
+ ast = 'def fred() case; when 3; end; end'.to_reek_source.syntax_tree
36
+ ctx = CodeContext.new(nil, ast)
37
+ @detector.conditional_counts(ctx).length.should == 0
38
+ end
39
+ end
40
+
29
41
  context 'with three identical conditionals' do
30
42
  before :each do
31
- cond = '@field == :sym'
32
- @cond_expr = cond.to_reek_source.syntax_tree
43
+ @cond = '@field == :sym'
44
+ @cond_expr = @cond.to_reek_source.syntax_tree
33
45
  src = <<EOS
34
46
  class Scrunch
35
47
  def first
36
- return #{cond} ? 0 : 3;
48
+ puts "hello" if @debug
49
+ return #{@cond} ? 0 : 3;
37
50
  end
38
51
  def second
39
- if #{cond}
52
+ if #{@cond}
40
53
  @other += " quarts"
41
54
  end
42
55
  end
43
56
  def third
44
- raise 'flu!' unless #{cond}
57
+ raise 'flu!' unless #{@cond}
45
58
  end
46
59
  end
47
60
  EOS
48
61
 
49
62
  ast = src.to_reek_source.syntax_tree
50
- ctx = CodeContext.new(nil, ast)
51
- @conds = @detector.conditional_counts(ctx)
63
+ @ctx = CodeContext.new(nil, ast)
64
+ @conds = @detector.conditional_counts(@ctx)
52
65
  end
53
- it 'finds one matching conditional' do
54
- @conds.length.should == 1
55
- end
56
- it 'returns the condition expr' do
57
- @conds.keys[0].should == @cond_expr
66
+ it 'finds both conditionals' do
67
+ @conds.length.should == 2
58
68
  end
59
69
  it 'knows there are three copies' do
60
- @conds[@cond_expr].should == 3
70
+ @conds[@cond_expr].length.should == 3
71
+ end
72
+
73
+ context 'looking at the YAML' do
74
+ before :each do
75
+ @detector.examine(@ctx)
76
+ warning = @detector.smells_found.to_a[0] # SMELL: too cumbersome!
77
+ @yaml = warning.to_yaml
78
+ end
79
+ it 'reports the source' do
80
+ @yaml.should match(/source:\s*#{@source_name}/)
81
+ end
82
+ it 'reports the class' do
83
+ @yaml.should match(/class:\s*SimulatedPolymorphism/)
84
+ end
85
+ it 'reports the subclass' do
86
+ @yaml.should match(/subclass:\s*RepeatedConditional/)
87
+ end
88
+ it 'reports the expression' do
89
+ @yaml.should match(/expression:\s*\(#{@cond}\)/)
90
+ end
91
+ it 'reports the number of occurrences' do
92
+ @yaml.should match(/occurrences:\s*3/)
93
+ end
94
+ it 'reports the referring lines' do
95
+ @yaml.should match(/lines:\s*- 4\s*- 7\s*- 12/)
96
+ end
61
97
  end
62
98
  end
63
99
 
@@ -90,7 +126,7 @@ EOS
90
126
  @conds.keys[0].should == @cond_expr
91
127
  end
92
128
  it 'knows there are three copies' do
93
- @conds[@cond_expr].should == 2
129
+ @conds[@cond_expr].length.should == 2
94
130
  end
95
131
  end
96
132
 
@@ -0,0 +1,42 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'smell_configuration')
3
+
4
+ include Reek::Core
5
+
6
+ shared_examples_for 'SmellDetector' do
7
+ context 'exception matching follows the context' do
8
+ before :each do
9
+ @ctx = mock('context')
10
+ # @ctx.should_receive(:exp).and_return(nil)
11
+ @ctx.should_receive(:config).and_return({})
12
+ end
13
+ it 'when false' do
14
+ @ctx.should_receive(:matches?).at_least(:once).and_return(false)
15
+ @detector.exception?(@ctx).should == false
16
+ end
17
+
18
+ it 'when true' do
19
+ @ctx.should_receive(:matches?).at_least(:once).and_return(true)
20
+ @detector.exception?(@ctx).should == true
21
+ end
22
+ end
23
+
24
+ context 'configuration' do
25
+ it 'becomes disabled when disabled' do
26
+ @detector.configure_with({SmellConfiguration::ENABLED_KEY => false})
27
+ @detector.should_not be_enabled
28
+ end
29
+ end
30
+ end
31
+
32
+ shared_examples_for 'common fields set correctly' do
33
+ it 'reports the source' do
34
+ @warning.source.should == @source_name
35
+ end
36
+ it 'reports the class' do
37
+ @warning.smell_class.should == @detector.class::SMELL_CLASS
38
+ end
39
+ it 'reports the subclass' do
40
+ @warning.subclass.should == @detector.class::SMELL_SUBCLASS
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'uncommunicative_method_name')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'code_parser')
5
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'sniffer')
6
+
7
+ include Reek
8
+ include Reek::Smells
9
+
10
+ describe UncommunicativeMethodName do
11
+ before :each do
12
+ @source_name = 'wallamalloo'
13
+ @detector = UncommunicativeMethodName.new(@source_name)
14
+ end
15
+
16
+ it_should_behave_like 'SmellDetector'
17
+
18
+ ['help', '+', '-', '/', '*'].each do |method_name|
19
+ it "accepts the method name '#{method_name}'" do
20
+ "def #{method_name}(fred) basics(17) end".should_not smell_of(UncommunicativeMethodName)
21
+ end
22
+ end
23
+
24
+ ['x', 'x2', 'method2'].each do |method_name|
25
+ context 'with a bad name' do
26
+ before :each do
27
+ src = 'def x() end'
28
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
29
+ @smells = @detector.examine_context(ctx)
30
+ @warning = @smells[0]
31
+ end
32
+
33
+ it_should_behave_like 'common fields set correctly'
34
+
35
+ it 'reports the correct values' do
36
+ @smells[0].smell[UncommunicativeMethodName::METHOD_NAME_KEY].should == 'x'
37
+ @smells[0].lines.should == [1]
38
+ @smells[0].context.should == 'x'
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'uncommunicative_module_name')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'code_parser')
5
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'sniffer')
6
+
7
+ include Reek
8
+ include Reek::Smells
9
+
10
+ describe UncommunicativeModuleName do
11
+ before :each do
12
+ @source_name = 'classy'
13
+ @detector = UncommunicativeModuleName.new(@source_name)
14
+ end
15
+
16
+ it_should_behave_like 'SmellDetector'
17
+
18
+ ['class', 'module'].each do |type|
19
+ it 'does not report one-word name' do
20
+ "#{type} Helper; end".should_not reek_of(:UncommunicativeModuleName)
21
+ end
22
+ it 'reports one-letter name' do
23
+ "#{type} X; end".should reek_of(:UncommunicativeModuleName, /X/)
24
+ end
25
+ it 'reports name of the form "x2"' do
26
+ "#{type} X2; end".should reek_of(:UncommunicativeModuleName, /X2/)
27
+ end
28
+ it 'reports long name ending in a number' do
29
+ "#{type} Printer2; end".should reek_of(:UncommunicativeModuleName, /Printer2/)
30
+ end
31
+ it 'reports a bad scoped name' do
32
+ src = "#{type} Foo::X; end"
33
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
34
+ smells = @detector.examine_context(ctx)
35
+ smells.length.should == 1
36
+ smells[0].smell_class.should == UncommunicativeModuleName::SMELL_CLASS
37
+ smells[0].subclass.should == UncommunicativeModuleName::SMELL_SUBCLASS
38
+ smells[0].smell[UncommunicativeModuleName::MODULE_NAME_KEY].should == 'X'
39
+ smells[0].context.should match(/#{smells[0].smell[UncommunicativeModuleName::MODULE_NAME_KEY]}/)
40
+ end
41
+ end
42
+
43
+ context 'accepting names' do
44
+ it 'accepts Inline::C' do
45
+ src = 'module Inline::C; end'
46
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
47
+ @detector.examine_context(ctx).should be_empty
48
+ end
49
+ end
50
+
51
+ context 'looking at the YAML' do
52
+ before :each do
53
+ src = 'module Printer2; end'
54
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
55
+ smells = @detector.examine_context(ctx)
56
+ @warning = smells[0]
57
+ end
58
+
59
+ it_should_behave_like 'common fields set correctly'
60
+
61
+ it 'reports the correct values' do
62
+ @warning.smell[UncommunicativeModuleName::MODULE_NAME_KEY].should == 'Printer2'
63
+ @warning.lines.should == [1]
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,71 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'uncommunicative_parameter_name')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'method_context')
5
+
6
+ include Reek::Core
7
+ include Reek::Smells
8
+
9
+ describe UncommunicativeParameterName do
10
+ before :each do
11
+ @source_name = 'wallamalloo'
12
+ @detector = UncommunicativeParameterName.new(@source_name)
13
+ end
14
+
15
+ it_should_behave_like 'SmellDetector'
16
+
17
+ context "parameter name" do
18
+ ['obj.', ''].each do |host|
19
+ it 'does not recognise *' do
20
+ "def #{host}help(xray, *) basics(17) end".should_not smell_of(UncommunicativeParameterName)
21
+ end
22
+ it "reports parameter's name" do
23
+ src = "def #{host}help(x) basics(17) end"
24
+ src.should smell_of(UncommunicativeParameterName, {UncommunicativeParameterName::PARAMETER_NAME_KEY => 'x'})
25
+ end
26
+
27
+ context 'with a name of the form "x2"' do
28
+ before :each do
29
+ @bad_param = 'x2'
30
+ src = "def #{host}help(#{@bad_param}) basics(17) end"
31
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
32
+ @smells = @detector.examine_context(ctx)
33
+ end
34
+ it 'reports only 1 smell' do
35
+ @smells.length.should == 1
36
+ end
37
+ it 'reports uncommunicative parameter name' do
38
+ @smells[0].subclass.should == UncommunicativeParameterName::SMELL_SUBCLASS
39
+ end
40
+ it 'reports the parameter name' do
41
+ @smells[0].smell[UncommunicativeParameterName::PARAMETER_NAME_KEY].should == @bad_param
42
+ end
43
+ end
44
+ it 'reports long name ending in a number' do
45
+ @bad_param = 'param2'
46
+ src = "def #{host}help(#{@bad_param}) basics(17) end"
47
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
48
+ smells = @detector.examine_context(ctx)
49
+ smells.length.should == 1
50
+ smells[0].subclass.should == UncommunicativeParameterName::SMELL_SUBCLASS
51
+ smells[0].smell[UncommunicativeParameterName::PARAMETER_NAME_KEY].should == @bad_param
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'looking at the YAML' do
57
+ before :each do
58
+ src = 'def bad(good, bad2, good_again) end'
59
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
60
+ @smells = @detector.examine_context(ctx)
61
+ @warning = @smells[0]
62
+ end
63
+
64
+ it_should_behave_like 'common fields set correctly'
65
+
66
+ it 'reports the correct values' do
67
+ @warning.smell[UncommunicativeParameterName::PARAMETER_NAME_KEY].should == 'bad2'
68
+ @warning.lines.should == [1]
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,120 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'uncommunicative_variable_name')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'code_parser')
5
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'sniffer')
6
+
7
+ include Reek
8
+ include Reek::Smells
9
+
10
+ describe UncommunicativeVariableName do
11
+ before :each do
12
+ @source_name = 'wallamalloo'
13
+ @detector = UncommunicativeVariableName.new(@source_name)
14
+ end
15
+
16
+ it_should_behave_like 'SmellDetector'
17
+
18
+ context "field name" do
19
+ it 'does not report use of one-letter fieldname' do
20
+ src = 'class Thing; def simple(fred) @x end end'
21
+ src.should_not smell_of(UncommunicativeVariableName)
22
+ end
23
+ it 'reports one-letter fieldname in assignment' do
24
+ src = 'class Thing; def simple(fred) @x = fred end end'
25
+ src.should reek_of(:UncommunicativeVariableName, /@x/, /Thing/, /variable name/)
26
+ end
27
+ end
28
+
29
+ context "local variable name" do
30
+ it 'does not report one-word variable name' do
31
+ 'def help(fred) simple = jim(45) end'.should_not smell_of(UncommunicativeVariableName)
32
+ end
33
+ it 'reports one-letter variable name' do
34
+ src = 'def simple(fred) x = jim(45) end'
35
+ src.should smell_of(UncommunicativeVariableName,
36
+ {UncommunicativeVariableName::VARIABLE_NAME_KEY => 'x'})
37
+ end
38
+ it 'reports name of the form "x2"' do
39
+ src = 'def simple(fred) x2 = jim(45) end'
40
+ src.should smell_of(UncommunicativeVariableName,
41
+ {UncommunicativeVariableName::VARIABLE_NAME_KEY => 'x2'})
42
+ end
43
+ it 'reports long name ending in a number' do
44
+ @bad_var = 'var123'
45
+ src = "def simple(fred) #{@bad_var} = jim(45) end"
46
+ src.should smell_of(UncommunicativeVariableName,
47
+ {UncommunicativeVariableName::VARIABLE_NAME_KEY => @bad_var})
48
+ end
49
+ it 'reports variable name only once' do
50
+ src = 'def simple(fred) x = jim(45); x = y end'
51
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
52
+ smells = @detector.examine_context(ctx)
53
+ smells.length.should == 1
54
+ smells[0].subclass.should == UncommunicativeVariableName::SMELL_SUBCLASS
55
+ smells[0].smell[UncommunicativeVariableName::VARIABLE_NAME_KEY].should == 'x'
56
+ smells[0].lines.should == [1,1]
57
+ end
58
+ it 'reports a bad name inside a block' do
59
+ src = 'def clean(text) text.each { q2 = 3 } end'
60
+ src.should smell_of(UncommunicativeVariableName,
61
+ {UncommunicativeVariableName::VARIABLE_NAME_KEY => 'q2'})
62
+ end
63
+ it 'reports variable name outside any method' do
64
+ 'class Simple; x = jim(45); end'.should reek_of(:UncommunicativeVariableName, /x/)
65
+ end
66
+ end
67
+
68
+ context "block parameter name" do
69
+ it "reports deep block parameter" do
70
+ src = <<EOS
71
+ def bad
72
+ unless @mod then
73
+ @sig.each { |x| x.to_s }
74
+ end
75
+ end
76
+ EOS
77
+ src.should smell_of(UncommunicativeVariableName,
78
+ {UncommunicativeVariableName::VARIABLE_NAME_KEY => 'x'})
79
+ end
80
+ end
81
+
82
+ context 'when a smell is reported' do
83
+ before :each do
84
+ src = <<EOS
85
+ def bad
86
+ unless @mod then
87
+ x2 = xy.to_s
88
+ x2
89
+ x2 = 56
90
+ end
91
+ end
92
+ EOS
93
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
94
+ @smells = @detector.examine_context(ctx)
95
+ @warning = @smells[0]
96
+ end
97
+
98
+ it_should_behave_like 'common fields set correctly'
99
+
100
+ it 'reports the correct values' do
101
+ @warning.smell['variable_name'].should == 'x2'
102
+ @warning.lines.should == [3,5]
103
+ end
104
+ end
105
+
106
+ context 'when a smell is reported in a singleton method' do
107
+ before :each do
108
+ src = 'def self.bad() x2 = 4; end'
109
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
110
+ @smells = @detector.examine_context(ctx)
111
+ @warning = @smells[0]
112
+ end
113
+
114
+ it_should_behave_like 'common fields set correctly'
115
+
116
+ it 'reports the fq context' do
117
+ @warning.context.should == 'self.bad'
118
+ end
119
+ end
120
+ end
@@ -1,14 +1,32 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
-
3
- require 'reek/smells/utility_function'
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smells', 'utility_function')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
4
 
5
5
  include Reek
6
6
  include Reek::Smells
7
7
 
8
8
  describe UtilityFunction do
9
+ before(:each) do
10
+ @source_name = 'loser'
11
+ @detector = UtilityFunction.new(@source_name)
12
+ end
13
+
14
+ it_should_behave_like 'SmellDetector'
15
+
16
+ context 'with a singleton method' do
17
+ ['self', 'local_call', '$global'].each do |receiver|
18
+ it 'ignores the receiver' do
19
+ src = "def #{receiver}.simple(arga) arga.to_s + arga.to_i end"
20
+ ctx = MethodContext.new(nil, src.to_reek_source.syntax_tree)
21
+ @detector.examine_context(ctx).should be_empty
22
+ end
23
+ end
24
+ end
9
25
  context 'with no calls' do
10
26
  it 'does not report empty method' do
11
- 'def simple(arga) end'.should_not reek
27
+ src = 'def simple(arga) end'
28
+ ctx = MethodContext.new(nil, src.to_reek_source.syntax_tree)
29
+ @detector.examine_context(ctx).should be_empty
12
30
  end
13
31
  it 'does not report literal' do
14
32
  'def simple(arga) 3; end'.should_not reek
@@ -25,6 +43,10 @@ describe UtilityFunction do
25
43
  it 'recognises an ivar reference within a block' do
26
44
  'def clean(text) text.each { @fred = 3} end'.should_not reek
27
45
  end
46
+ it 'copes with nil superclass' do
47
+ '# clean class for testing purposes
48
+ class Object; def is_maybe?() false end end'.should_not reek
49
+ end
28
50
  end
29
51
 
30
52
  context 'with only one call' do
@@ -40,6 +62,9 @@ describe UtilityFunction do
40
62
  it 'reports two calls' do
41
63
  'def simple(arga) arga.to_s + arga.to_i end'.should reek_of(:UtilityFunction, /simple/)
42
64
  end
65
+ it 'counts a local call in a param initializer' do
66
+ 'def simple(arga=local) arga.to_s end'.should_not reek_of(:UtilityFunction)
67
+ end
43
68
  it 'should count usages of self'do
44
69
  'def <=>(other) Options[:sort_order].compare(self, other) end'.should_not reek
45
70
  end
@@ -59,6 +84,7 @@ describe UtilityFunction do
59
84
 
60
85
  it 'should recognise a deep call' do
61
86
  src = <<EOS
87
+ # clean class for testing purposes
62
88
  class Red
63
89
  def deep(text)
64
90
  text.each { |mod| atts = shelve(mod) }
@@ -72,4 +98,24 @@ EOS
72
98
  src.should_not reek
73
99
  end
74
100
  end
101
+
102
+ context 'when a smells is reported' do
103
+ before :each do
104
+ src = <<EOS
105
+ def simple(arga)
106
+ arga.b.c
107
+ end
108
+ EOS
109
+ source = src.to_reek_source
110
+ sniffer = Sniffer.new(source)
111
+ mctx = CodeParser.new(sniffer).process_defn(source.syntax_tree)
112
+ @warning = @detector.examine_context(mctx)[0] # SMELL: too cumbersome!
113
+ end
114
+
115
+ it_should_behave_like 'common fields set correctly'
116
+
117
+ it 'reports the line number of the method' do
118
+ @warning.lines.should == [1]
119
+ end
120
+ end
75
121
  end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'source', 'code_comment')
3
+
4
+ include Reek::Source
5
+
6
+ describe CodeComment do
7
+ context 'with an empty comment' do
8
+ before :each do
9
+ @comment = CodeComment.new('')
10
+ end
11
+ it 'is not descriptive' do
12
+ @comment.is_descriptive?.should be_false
13
+ end
14
+ it 'has an empty config' do
15
+ @comment.config.should be_empty
16
+ end
17
+ end
18
+
19
+ context 'comment checks' do
20
+ it 'rejects an empty comment' do
21
+ CodeComment.new('#').is_descriptive?.should be_false
22
+ end
23
+ it 'rejects a 1-word comment' do
24
+ CodeComment.new("# fred\n# ").is_descriptive?.should be_false
25
+ end
26
+ it 'accepts a 2-word comment' do
27
+ CodeComment.new('# fred here ').is_descriptive?.should be_true
28
+ end
29
+ it 'accepts a multi-word comment' do
30
+ CodeComment.new("# fred here \n# with \n # biscuits ").is_descriptive?.should be_true
31
+ end
32
+ end
33
+
34
+ context 'comment config' do
35
+ it 'parses hashed options' do
36
+ config = CodeComment.new("# :reek:Duplication: { enabled: false }").config
37
+ config.should include('Duplication')
38
+ config['Duplication'].should include('enabled')
39
+ config['Duplication']['enabled'].should be_false
40
+ end
41
+ it 'parses hashed options with ruby names' do
42
+ config = CodeComment.new("# :reek:nested_iterators: { enabled: true }").config
43
+ config.should include('NestedIterators')
44
+ config['NestedIterators'].should include('enabled')
45
+ config['NestedIterators']['enabled'].should be_true
46
+ end
47
+ it 'parses multiple hashed options' do
48
+ config = CodeComment.new("# :reek:Duplication: { enabled: false }\n:reek:nested_iterators: { enabled: true }").config
49
+ config.should include('Duplication','NestedIterators')
50
+ config['Duplication'].should include('enabled')
51
+ config['Duplication']['enabled'].should be_false
52
+ config['NestedIterators'].should include('enabled')
53
+ config['NestedIterators']['enabled'].should be_true
54
+ end
55
+ it 'parses multiple hashed options on the same line' do
56
+ config = CodeComment.new("# :reek:Duplication: { enabled: false } and :reek:nested_iterators: { enabled: true }").config
57
+ config.should include('Duplication','NestedIterators')
58
+ config['Duplication'].should include('enabled')
59
+ config['Duplication']['enabled'].should be_false
60
+ config['NestedIterators'].should include('enabled')
61
+ config['NestedIterators']['enabled'].should be_true
62
+ end
63
+ it 'parses multiple unhashed options on the same line' do
64
+ config = CodeComment.new("# :reek:Duplication and :reek:nested_iterators").config
65
+ config.should include('Duplication','NestedIterators')
66
+ config['Duplication'].should include('enabled')
67
+ config['Duplication']['enabled'].should be_false
68
+ config['NestedIterators'].should include('enabled')
69
+ config['NestedIterators']['enabled'].should be_false
70
+ end
71
+ it 'disables the smell if no options are specifed' do
72
+ config = CodeComment.new("# :reek:Duplication").config
73
+ config.should include('Duplication')
74
+ config['Duplication'].should include('enabled')
75
+ config['Duplication']['enabled'].should be_false
76
+ end
77
+ it 'ignores smells after a space' do
78
+ config = CodeComment.new("# :reek: Duplication").config
79
+ config.should_not include('Duplication')
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
2
+
3
+ include Reek
4
+
5
+ describe Dir do
6
+ it 'reports correct smells via the Dir matcher' do
7
+ files = Dir['spec/samples/two_smelly_files/*.rb']
8
+ files.should reek
9
+ files.should reek_of(:UncommunicativeVariableName)
10
+ files.should_not reek_of(:LargeClass)
11
+ end
12
+
13
+ it 'copes with daft file specs' do
14
+ Dir["spec/samples/two_smelly_files/*/.rb"].should_not reek
15
+ end
16
+
17
+ it 'copes with empty array' do
18
+ [].should_not reek
19
+ end
20
+ end