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
@@ -0,0 +1,58 @@
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', 'irresponsible_module')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+
5
+ include Reek::Smells
6
+
7
+ describe IrresponsibleModule do
8
+ before(:each) do
9
+ @bad_module_name = 'WrongUn'
10
+ @detector = IrresponsibleModule.new('yoof')
11
+ end
12
+
13
+ it_should_behave_like 'SmellDetector'
14
+
15
+ it "does not report a class having a comment" do
16
+ src = <<EOS
17
+ # test class
18
+ class Responsible; end
19
+ EOS
20
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
21
+ @detector.examine_context(ctx).should be_empty
22
+ end
23
+ it "reports a class without a comment" do
24
+ src = "class #{@bad_module_name}; end"
25
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
26
+ smells = @detector.examine_context(ctx)
27
+ smells.length.should == 1
28
+ smells[0].smell_class.should == IrresponsibleModule::SMELL_CLASS
29
+ smells[0].subclass.should == IrresponsibleModule::SMELL_SUBCLASS
30
+ smells[0].lines.should == [1]
31
+ smells[0].smell[IrresponsibleModule::MODULE_NAME_KEY].should == @bad_module_name
32
+ end
33
+ it "reports a class with an empty comment" do
34
+ src = <<EOS
35
+ #
36
+ #
37
+ #
38
+ class #{@bad_module_name}; end
39
+ EOS
40
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
41
+ smells = @detector.examine_context(ctx)
42
+ smells.length.should == 1
43
+ smells[0].smell_class.should == IrresponsibleModule::SMELL_CLASS
44
+ smells[0].subclass.should == IrresponsibleModule::SMELL_SUBCLASS
45
+ smells[0].lines.should == [4]
46
+ smells[0].smell[IrresponsibleModule::MODULE_NAME_KEY].should == @bad_module_name
47
+ end
48
+ it 'reports a fq module name correctly' do
49
+ src = 'class Foo::Bar; end'
50
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
51
+ smells = @detector.examine_context(ctx)
52
+ smells.length.should == 1
53
+ smells[0].smell_class.should == IrresponsibleModule::SMELL_CLASS
54
+ smells[0].subclass.should == IrresponsibleModule::SMELL_SUBCLASS
55
+ smells[0].smell[IrresponsibleModule::MODULE_NAME_KEY].should == 'Foo::Bar'
56
+ smells[0].context.should match(/#{smells[0].smell[IrresponsibleModule::MODULE_NAME_KEY]}/)
57
+ end
58
+ end
@@ -1,78 +1,43 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
-
3
- require 'reek/class_context'
4
- require 'reek/stop_context'
5
- require 'reek/code_parser'
6
- require 'reek/smells/large_class'
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', 'large_class')
3
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'examiner')
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.expand_path(__FILE__)), 'smell_detector_shared')
7
6
 
8
7
  include Reek
9
8
  include Reek::Smells
10
9
 
11
- describe LargeClass, 'when exceptions are listed' do
10
+ describe LargeClass do
12
11
  before(:each) do
13
- @class_name = 'Humungous'
14
- src = <<EOS
15
- class #{@class_name}
16
- def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
17
- def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
18
- def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
19
- def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
20
- def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
21
- def me51x()3 end
22
- end
23
- EOS
24
- @ctx = ClassContext.from_s(src)
25
- @config = LargeClass.default_config
26
- end
27
-
28
- it 'should ignore first excepted name' do
29
- @config[LargeClass::EXCLUDE_KEY] = [@class_name]
30
- lc = LargeClass.new(@config)
31
- lc.examine(@ctx).should == false
32
- end
33
-
34
- it 'should ignore second excepted name' do
35
- @config[LargeClass::EXCLUDE_KEY] = ['Oversized', @class_name]
36
- lc = LargeClass.new(@config)
37
- lc.examine(@ctx).should == false
12
+ @source_name = 'elephant'
13
+ @detector = LargeClass.new(@source_name)
38
14
  end
39
15
 
40
- it 'should report non-excepted name' do
41
- @config[LargeClass::EXCLUDE_KEY] = ['SmellMe']
42
- lc = LargeClass.new(@config)
43
- lc.examine(@ctx).should == true
44
- end
45
- end
46
-
47
- describe LargeClass, 'checking source code' do
16
+ it_should_behave_like 'SmellDetector'
48
17
 
49
18
  context 'counting instance variables' do
50
- it 'should not report empty class' do
51
- ClassContext.from_s('class Empty;end').should have(0).variable_names
52
- end
53
-
54
- it 'should count ivars in one method' do
55
- ClassContext.from_s('class Empty;def ivars() @aa=@ab=@ac=@ad; end;end').should have(4).variable_names
19
+ it 'should not report 9 ivars' do
20
+ '# clean class for testing purposes
21
+ class Empty;def ivars() @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=4; end;end'.should_not reek
56
22
  end
57
23
 
58
- it 'should count ivars in 2 methods' do
59
- ClassContext.from_s('class Empty;def iv1() @aa=@ab; end;def iv2() @aa=@ac; end;end').should have(3).variable_names
60
- end
61
-
62
- it 'should not report 9 ivars' do
63
- 'class Empty;def ivars() @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai; end;end'.should_not reek
24
+ it 'counts each ivar only once' do
25
+ '# clean class for testing purposes
26
+ class Empty;def ivars() @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=4;@aa=3; end;end'.should_not reek
64
27
  end
65
28
 
66
29
  it 'should report 10 ivars' do
67
- 'class Empty;def ivars() @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=@aj; end;end'.should reek_of(:LargeClass)
30
+ '# smelly class for testing purposes
31
+ class Empty;def ivars() @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=@aj=4; end;end'.should reek_only_of(:LargeClass)
68
32
  end
69
33
 
70
34
  it 'should not report 10 ivars in 2 extensions' do
71
35
  src = <<EOS
36
+ # clean class for testing purposes
72
37
  class Full;def ivars_a() @aa=@ab=@ac=@ad=@ae; end;end
38
+ # clean class for testing purposes
73
39
  class Full;def ivars_b() @af=@ag=@ah=@ai=@aj; end;end
74
40
  EOS
75
-
76
41
  src.should_not reek
77
42
  end
78
43
  end
@@ -81,6 +46,7 @@ EOS
81
46
 
82
47
  it 'should not report 25 methods' do
83
48
  src = <<EOS
49
+ # smelly class for testing purposes
84
50
  class Full
85
51
  def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
86
52
  def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
@@ -89,7 +55,8 @@ class Full
89
55
  def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
90
56
  end
91
57
  EOS
92
- src.should_not reek
58
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
59
+ @detector.examine_context(ctx).should be_empty
93
60
  end
94
61
 
95
62
  it 'should report 26 methods' do
@@ -103,7 +70,11 @@ class Full
103
70
  def me51x()3 end
104
71
  end
105
72
  EOS
106
- src.should reek_of(:LargeClass)
73
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
74
+ smells = @detector.examine_context(ctx)
75
+ smells.length.should == 1
76
+ smells[0].subclass.should == LargeClass::SUBCLASS_TOO_MANY_METHODS
77
+ smells[0].smell[LargeClass::METHOD_COUNT_KEY].should == 26
107
78
  end
108
79
  end
109
80
 
@@ -119,7 +90,46 @@ class Full
119
90
  def me51x()3 end
120
91
  end
121
92
  EOS
122
- src.should_not reek_of(:LargeClass)
93
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
94
+ @detector.examine_context(ctx).should be_empty
123
95
  end
124
96
  end
97
+
98
+ it 'reports correctly when the class has many methods' do
99
+ src = <<EOS
100
+ class Full
101
+ def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
102
+ def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
103
+ def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
104
+ def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
105
+ def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
106
+ def me51x()3 end
107
+ end
108
+ EOS
109
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
110
+ @warning = @detector.examine_context(ctx)[0]
111
+ @warning.source.should == @source_name
112
+ @warning.smell_class.should == 'LargeClass'
113
+ @warning.subclass.should == LargeClass::SUBCLASS_TOO_MANY_METHODS
114
+ @warning.smell[LargeClass::METHOD_COUNT_KEY].should == 26
115
+ @warning.lines.should == [1]
116
+ end
117
+
118
+ it 'reports correctly when the class has 30 instance variables' do
119
+ src = <<EOS
120
+ # smelly class for testing purposes
121
+ class Empty
122
+ def ivars
123
+ @aa=@ab=@ac=@ad=@ae=@af=@ag=@ah=@ai=@aj=4
124
+ end
125
+ end
126
+ EOS
127
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
128
+ @warning = @detector.examine_context(ctx)[0]
129
+ @warning.source.should == @source_name
130
+ @warning.smell_class.should == 'LargeClass'
131
+ @warning.subclass.should == LargeClass::SUBCLASS_TOO_MANY_IVARS
132
+ @warning.smell[LargeClass::IVAR_COUNT_KEY].should == 10
133
+ @warning.lines.should == [2]
134
+ end
125
135
  end
@@ -1,29 +1,32 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
-
3
- require 'reek/code_parser'
4
- require 'reek/sniffer'
5
- require 'reek/smells/long_method'
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', 'long_method')
3
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'code_parser')
4
+ require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'sniffer')
5
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
6
6
 
7
7
  include Reek
8
8
  include Reek::Smells
9
9
 
10
10
  def process_method(src)
11
11
  source = src.to_reek_source
12
- sniffer = Sniffer.new(source)
13
- CodeParser.new(sniffer).process_defn(source.syntax_tree)
12
+ sniffer = Core::Sniffer.new(source)
13
+ Core::CodeParser.new(sniffer).process_defn(source.syntax_tree)
14
14
  end
15
15
 
16
16
  describe LongMethod do
17
17
  it 'should not report short methods' do
18
- 'def short(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;end'.should_not reek
18
+ src = 'def short(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;end'
19
+ src.should_not smell_of(LongMethod)
19
20
  end
20
21
 
21
22
  it 'should report long methods' do
22
- 'def long(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end'.should reek_only_of(:LongMethod, /6 statements/)
23
+ src = 'def long(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end'
24
+ src.should reek_only_of(:LongMethod, /6 statements/)
23
25
  end
24
26
 
25
27
  it 'should not report initialize' do
26
- 'def initialize(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end'.should_not reek
28
+ src = 'def initialize(arga) alf = f(1);@bet = 2;@cut = 3;@dit = 4; @emp = 5;@fry = 6;end'
29
+ src.should_not smell_of(LongMethod)
27
30
  end
28
31
 
29
32
  it 'should only report a long method once' do
@@ -194,3 +197,30 @@ EOS
194
197
  method.num_statements.should == 6
195
198
  end
196
199
  end
200
+
201
+ describe LongMethod do
202
+ before(:each) do
203
+ @detector = LongMethod.new('silver')
204
+ end
205
+
206
+ it_should_behave_like 'SmellDetector'
207
+
208
+ context 'when the method has 30 statements' do
209
+ before :each do
210
+ @num_statements = 30
211
+ ctx = mock('method_context', :null_object => true)
212
+ ctx.should_receive(:num_statements).and_return(@num_statements)
213
+ ctx.should_receive(:config).and_return({})
214
+ @smells = @detector.examine_context(ctx)
215
+ end
216
+ it 'reports only 1 smell' do
217
+ @smells.length.should == 1
218
+ end
219
+ it 'reports the number of statements' do
220
+ @smells[0].smell[LongMethod::STATEMENT_COUNT_KEY].should == @num_statements
221
+ end
222
+ it 'reports the correct subclass' do
223
+ @smells[0].subclass.should == LongMethod::SUBCLASS_TOO_MANY_STATEMENTS
224
+ end
225
+ end
226
+ end
@@ -1,72 +1,94 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
-
3
- require 'reek/smells/long_parameter_list'
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', 'long_parameter_list')
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 LongParameterList do
9
-
10
- describe 'for methods with few parameters' do
9
+
10
+ context 'for methods with few parameters' do
11
11
  it 'should report nothing for no parameters' do
12
- 'def simple; f(3);true; end'.should_not reek
12
+ 'def simple; f(3);true; end'.should_not smell_of(LongParameterList)
13
13
  end
14
14
  it 'should report nothing for 1 parameter' do
15
- 'def simple(yep) f(3);true end'.should_not reek
15
+ 'def simple(yep) f(3);true end'.should_not smell_of(LongParameterList)
16
16
  end
17
17
  it 'should report nothing for 2 parameters' do
18
- 'def simple(yep,zero) f(3);true end'.should_not reek
18
+ 'def simple(yep,zero) f(3);true end'.should_not smell_of(LongParameterList)
19
19
  end
20
20
  it 'should not count an optional block' do
21
- 'def simple(alpha, yep, zero, &opt) f(3);true end'.should_not reek
21
+ 'def simple(alpha, yep, zero, &opt) f(3);true end'.should_not smell_of(LongParameterList)
22
22
  end
23
23
  it 'should not report inner block with too many parameters' do
24
- 'def simple(yep,zero); m[3]; rand(34); f.each { |arga, argb, argc, argd| true}; end'.should_not reek
24
+ src = 'def simple(yep,zero); m[3]; rand(34); f.each { |arga, argb, argc, argd| true}; end'
25
+ src.should_not smell_of(LongParameterList)
25
26
  end
26
27
 
27
28
  describe 'and default values' do
28
29
  it 'should report nothing for 1 parameter' do
29
- 'def simple(zero=nil) f(3);false end'.should_not reek
30
+ 'def simple(zero=nil) f(3);false end'.should_not smell_of(LongParameterList)
30
31
  end
31
32
  it 'should report nothing for 2 parameters with 1 default' do
32
- 'def simple(yep, zero=nil) f(3);false end'.should_not reek
33
+ 'def simple(yep, zero=nil) f(3);false end'.should_not smell_of(LongParameterList)
33
34
  end
34
35
  it 'should report nothing for 2 defaulted parameters' do
35
- 'def simple(yep=4, zero=nil) f(3);false end'.should_not reek
36
+ 'def simple(yep=4, zero=nil) f(3);false end'.should_not smell_of(LongParameterList)
36
37
  end
37
38
  end
38
39
  end
39
40
 
40
41
  describe 'for methods with too many parameters' do
41
42
  it 'should report 4 parameters' do
42
- 'def simple(arga, argb, argc, argd) f(3);true end'.should reek_only_of(:LongParameterList, /4 parameters/)
43
+ src = 'def simple(arga, argb, argc, argd) f(3);true end'
44
+ src.should smell_of(LongParameterList, LongParameterList::PARAMETER_COUNT_KEY => 4)
43
45
  end
44
46
  it 'should report 8 parameters' do
45
- 'def simple(arga, argb, argc, argd,arge, argf, argg, argh) f(3);true end'.should reek_only_of(:LongParameterList, /8 parameters/)
47
+ src = 'def simple(arga, argb, argc, argd,arge, argf, argg, argh) f(3);true end'
48
+ src.should smell_of(LongParameterList, LongParameterList::PARAMETER_COUNT_KEY => 8)
46
49
  end
47
50
 
48
51
  describe 'and default values' do
49
52
  it 'should report 3 with 1 defaulted' do
50
- 'def simple(polly, queue, yep, zero=nil) f(3);false end'.should reek_only_of(:LongParameterList, /4 parameters/)
53
+ src = 'def simple(polly, queue, yep, zero=nil) f(3);false end'
54
+ src.should smell_of(LongParameterList, LongParameterList::PARAMETER_COUNT_KEY => 4)
51
55
  end
52
56
  it 'should report with 3 defaulted' do
53
- 'def simple(aarg, polly=2, yep=:truth, zero=nil) f(3);false end'.should reek_only_of(:LongParameterList, /4 parameters/)
57
+ src = 'def simple(aarg, polly=2, yep=:truth, zero=nil) f(3);false end'
58
+ src.should smell_of(LongParameterList, LongParameterList::PARAMETER_COUNT_KEY => 4)
54
59
  end
55
60
  end
56
61
  end
57
-
58
- describe 'yield' do
59
- it 'should not report yield with no parameters' do
60
- 'def simple(arga, argb, &blk) f(3);yield; end'.should_not reek
61
- end
62
- it 'should not report yield with few parameters' do
63
- 'def simple(arga, argb, &blk) f(3);yield a,b; end'.should_not reek
62
+ end
63
+
64
+ describe LongParameterList do
65
+ before(:each) do
66
+ @source_name = 'smokin'
67
+ @detector = LongParameterList.new(@source_name)
68
+ end
69
+
70
+ it_should_behave_like 'SmellDetector'
71
+
72
+ context 'when a smell is reported' do
73
+ before :each do
74
+ src = <<EOS
75
+ def badguy(arga, argb, argc, argd)
76
+ f(3)
77
+ true
78
+ end
79
+ EOS
80
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
81
+ @smells = @detector.examine_context(ctx)
82
+ @warning = @smells[0]
64
83
  end
65
- it 'should report yield with many parameters' do
66
- 'def simple(arga, argb, &blk) f(3);yield arga,argb,arga,argb; end'.should reek_only_of(:LongYieldList, /simple/, /yields/, /4/)
84
+
85
+ it_should_behave_like 'common fields set correctly'
86
+
87
+ it 'reports the number of parameters' do
88
+ @warning.smell[LongParameterList::PARAMETER_COUNT_KEY].should == 4
67
89
  end
68
- it 'should not report yield of a long expression' do
69
- 'def simple(arga, argb, &blk) f(3);yield(if @dec then argb else 5+3 end); end'.should_not reek
90
+ it 'reports the line number of the method' do
91
+ @warning.lines.should == [1]
70
92
  end
71
93
  end
72
94
  end
@@ -0,0 +1,57 @@
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', 'long_yield_list')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
+
5
+ include Reek
6
+ include Reek::Smells
7
+
8
+ describe LongYieldList do
9
+ before(:each) do
10
+ @source_name = 'oo la la'
11
+ @detector = LongYieldList.new(@source_name)
12
+ # SMELL: can't use the default config, because that contains an override,
13
+ # which causes the mocked matches?() method to be called twice!!
14
+ end
15
+
16
+ it_should_behave_like 'SmellDetector'
17
+
18
+ context 'yield' do
19
+ it 'should not report yield with no parameters' do
20
+ src = 'def simple(arga, argb, &blk) f(3);yield; end'
21
+ src.should_not smell_of(LongYieldList)
22
+ end
23
+ it 'should not report yield with few parameters' do
24
+ src = 'def simple(arga, argb, &blk) f(3);yield a,b; end'
25
+ src.should_not smell_of(LongYieldList)
26
+ end
27
+ it 'should report yield with many parameters' do
28
+ src = 'def simple(arga, argb, &blk) f(3);yield arga,argb,arga,argb; end'
29
+ src.should smell_of(LongYieldList, LongYieldList::PARAMETER_COUNT_KEY => 4)
30
+ end
31
+ it 'should not report yield of a long expression' do
32
+ src = 'def simple(arga, argb, &blk) f(3);yield(if @dec then argb else 5+3 end); end'
33
+ src.should_not smell_of(LongYieldList)
34
+ end
35
+ end
36
+
37
+ context 'when a smells is reported' do
38
+ before :each do
39
+ src = <<EOS
40
+ def simple(arga, argb, &blk)
41
+ f(3)
42
+ yield(arga,argb,arga,argb)
43
+ end
44
+ EOS
45
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
46
+ @smells = @detector.examine_context(ctx)
47
+ @warning = @smells[0]
48
+ end
49
+
50
+ it_should_behave_like 'common fields set correctly'
51
+
52
+ it 'reports the correct values' do
53
+ @warning.smell['parameter_count'].should == 4
54
+ @warning.lines.should == [3]
55
+ end
56
+ end
57
+ end
@@ -1,13 +1,28 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
-
3
- require 'reek/smells/nested_iterators'
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', 'nested_iterators')
3
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
4
4
 
5
5
  include Reek::Smells
6
6
 
7
7
  describe NestedIterators do
8
8
 
9
+ context 'with no iterators' do
10
+ it 'reports no smells' do
11
+ src = 'def fred() nothing = true; end'
12
+ src.should_not smell_of(NestedIterators)
13
+ end
14
+ end
15
+
16
+ context 'with one iterator' do
17
+ it 'reports no smells' do
18
+ src = 'def fred() nothing.each {|item| item}; end'
19
+ src.should_not smell_of(NestedIterators)
20
+ end
21
+ end
22
+
9
23
  it 'should report nested iterators in a method' do
10
- 'def bad(fred) @fred.each {|item| item.each {|ting| ting.ting} } end'.should reek_only_of(:NestedIterators)
24
+ src = 'def bad(fred) @fred.each {|item| item.each {|ting| ting.ting} } end'
25
+ src.should smell_of(NestedIterators)
11
26
  end
12
27
 
13
28
  it 'should not report method with successive iterators' do
@@ -17,7 +32,7 @@ def bad(fred)
17
32
  @jim.each {|ting| ting.each }
18
33
  end
19
34
  EOS
20
- src.should_not reek
35
+ src.should_not smell_of(NestedIterators)
21
36
  end
22
37
 
23
38
  it 'should not report method with chained iterators' do
@@ -26,7 +41,7 @@ def chained
26
41
  @sig.keys.sort_by { |xray| xray.to_s }.each { |min| md5 << min.to_s }
27
42
  end
28
43
  EOS
29
- src.should_not reek
44
+ src.should_not smell_of(NestedIterators)
30
45
  end
31
46
 
32
47
  it 'should report nested iterators only once per method' do
@@ -36,7 +51,100 @@ def bad(fred)
36
51
  @jim.each {|ting| ting.each {|piece| @hal.send} }
37
52
  end
38
53
  EOS
39
- src.should reek_only_of(:NestedIterators)
54
+ src.should smell_of(NestedIterators, {}, {})
40
55
  end
56
+
57
+ context 'when the allowed nesting depth is 3' do
58
+ before :each do
59
+ @config = {NestedIterators::MAX_ALLOWED_NESTING_KEY => 3}
60
+ end
61
+
62
+ it 'should not report nested iterators 2 levels deep' do
63
+ src = <<EOS
64
+ def bad(fred)
65
+ @fred.each {|one| one.each {|two| two.two} }
41
66
  end
67
+ EOS
68
+ src.should_not smell_of(NestedIterators).with_config(@config)
69
+ end
70
+
71
+ it 'should not report nested iterators 3 levels deep' do
72
+ src = <<EOS
73
+ def bad(fred)
74
+ @fred.each {|one| one.each {|two| two.each {|three| three.three} } }
75
+ end
76
+ EOS
77
+ src.should_not smell_of(NestedIterators).with_config(@config)
78
+ end
79
+
80
+ it 'should report nested iterators 4 levels deep' do
81
+ src = <<EOS
82
+ def bad(fred)
83
+ @fred.each {|one| one.each {|two| two.each {|three| three.each {|four| four.four} } } }
84
+ end
85
+ EOS
86
+ src.should smell_of(NestedIterators).with_config(@config)
87
+ end
88
+ end
89
+
90
+ context 'when ignoring iterators' do
91
+ before :each do
92
+ @config = {NestedIterators::IGNORE_ITERATORS_KEY => ['ignore_me']}
93
+ end
42
94
 
95
+ it 'should not report nesting the ignored iterator inside another' do
96
+ src = 'def bad(fred) @fred.each {|item| item.ignore_me {|ting| ting.ting} } end'
97
+ src.should_not smell_of(NestedIterators).with_config(@config)
98
+ end
99
+
100
+ it 'should not report nesting inside the ignored iterator' do
101
+ src = 'def bad(fred) @fred.ignore_me {|item| item.each {|ting| ting.ting} } end'
102
+ src.should_not smell_of(NestedIterators).with_config(@config)
103
+ end
104
+
105
+ it 'should report nested iterators inside the ignored iterator' do
106
+ src = 'def bad(fred) @fred.ignore_me {|item| item.each {|ting| ting.each {|other| other.other} } } end'
107
+ src.should smell_of(NestedIterators, NestedIterators::NESTING_DEPTH_KEY => 2).with_config(@config)
108
+ end
109
+
110
+ it 'should report nested iterators outside the ignored iterator' do
111
+ src = 'def bad(fred) @fred.each {|item| item.each {|ting| ting.ignore_me {|other| other.other} } } end'
112
+ src.should smell_of(NestedIterators, NestedIterators::NESTING_DEPTH_KEY => 2).with_config(@config)
113
+ end
114
+
115
+ it 'should report nested iterators with the ignored iterator between them' do
116
+ src = 'def bad(fred) @fred.each {|item| item.ignore_me {|ting| ting.ting {|other| other.other} } } end'
117
+ src.should smell_of(NestedIterators, NestedIterators::NESTING_DEPTH_KEY => 2).with_config(@config)
118
+ end
119
+ end
120
+ end
121
+
122
+ describe NestedIterators do
123
+ before(:each) do
124
+ @source_name = 'cuckoo'
125
+ @detector = NestedIterators.new(@source_name)
126
+ end
127
+
128
+ it_should_behave_like 'SmellDetector'
129
+
130
+ context 'when a smell is reported' do
131
+ before :each do
132
+ src = <<EOS
133
+ def fred()
134
+ nothing.each do |item|
135
+ again.each {|thing| item }
136
+ end
137
+ end
138
+ EOS
139
+ ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
140
+ @warning = @detector.examine_context(ctx)[0]
141
+ end
142
+
143
+ it_should_behave_like 'common fields set correctly'
144
+
145
+ it 'reports correct values' do
146
+ @warning.smell[NestedIterators::NESTING_DEPTH_KEY].should == 2
147
+ @warning.lines.should == [3]
148
+ end
149
+ end
150
+ end