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.
- data/.yardopts +10 -0
- data/History.txt +62 -0
- data/README.md +74 -0
- data/bin/reek +2 -2
- data/config/defaults.reek +44 -5
- data/features/api.feature +20 -0
- data/features/masking_smells.feature +60 -42
- data/features/options.feature +7 -2
- data/features/rake_task.feature +29 -22
- data/features/reports.feature +9 -41
- data/features/samples.feature +184 -196
- data/features/stdin.feature +5 -8
- data/features/step_definitions/reek_steps.rb +8 -4
- data/features/support/env.rb +2 -3
- data/features/yaml.feature +85 -0
- data/lib/reek/cli/application.rb +46 -0
- data/lib/reek/cli/command_line.rb +108 -0
- data/lib/reek/cli/help_command.rb +18 -0
- data/lib/reek/cli/reek_command.rb +37 -0
- data/lib/reek/cli/report.rb +58 -0
- data/lib/reek/cli/version_command.rb +19 -0
- data/lib/reek/cli/yaml_command.rb +32 -0
- data/lib/reek/core/code_context.rb +64 -0
- data/lib/reek/core/code_parser.rb +166 -0
- data/lib/reek/core/method_context.rb +84 -0
- data/lib/reek/core/module_context.rb +20 -0
- data/lib/reek/core/object_refs.rb +51 -0
- data/lib/reek/core/singleton_method_context.rb +20 -0
- data/lib/reek/core/smell_configuration.rb +62 -0
- data/lib/reek/core/sniffer.rb +105 -0
- data/lib/reek/core/stop_context.rb +30 -0
- data/lib/reek/core/warning_collector.rb +27 -0
- data/lib/reek/examiner.rb +104 -0
- data/lib/reek/rake/task.rb +142 -0
- data/lib/reek/smell_warning.rb +73 -23
- data/lib/reek/smells/attribute.rb +26 -21
- data/lib/reek/smells/boolean_parameter.rb +38 -0
- data/lib/reek/smells/class_variable.rb +22 -9
- data/lib/reek/smells/control_couple.rb +40 -16
- data/lib/reek/smells/data_clump.rb +114 -23
- data/lib/reek/smells/duplication.rb +55 -15
- data/lib/reek/smells/feature_envy.rb +16 -7
- data/lib/reek/smells/irresponsible_module.rb +37 -0
- data/lib/reek/smells/large_class.rb +37 -19
- data/lib/reek/smells/long_method.rb +20 -9
- data/lib/reek/smells/long_parameter_list.rb +22 -10
- data/lib/reek/smells/long_yield_list.rb +43 -7
- data/lib/reek/smells/nested_iterators.rb +68 -8
- data/lib/reek/smells/simulated_polymorphism.rb +26 -15
- data/lib/reek/smells/smell_detector.rb +29 -51
- data/lib/reek/smells/uncommunicative_method_name.rb +74 -0
- data/lib/reek/smells/uncommunicative_module_name.rb +74 -0
- data/lib/reek/smells/uncommunicative_parameter_name.rb +79 -0
- data/lib/reek/smells/uncommunicative_variable_name.rb +89 -0
- data/lib/reek/smells/utility_function.rb +51 -12
- data/lib/reek/smells.rb +29 -0
- data/lib/reek/source/code_comment.rb +37 -0
- data/lib/reek/source/config_file.rb +72 -0
- data/lib/reek/source/core_extras.rb +46 -0
- data/lib/reek/source/reference_collector.rb +28 -0
- data/lib/reek/source/sexp_formatter.rb +17 -0
- data/lib/reek/source/source_code.rb +44 -0
- data/lib/reek/source/source_file.rb +32 -0
- data/lib/reek/source/source_locator.rb +42 -0
- data/lib/reek/source/tree_dresser.rb +204 -0
- data/lib/reek/source.rb +18 -0
- data/lib/reek/spec/should_reek.rb +31 -0
- data/lib/reek/spec/should_reek_of.rb +37 -0
- data/lib/reek/spec/should_reek_only_of.rb +37 -0
- data/lib/reek/spec.rb +51 -0
- data/lib/reek.rb +8 -4
- data/reek.gemspec +9 -7
- data/spec/matchers/smell_of_matcher.rb +58 -0
- data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
- data/spec/reek/cli/reek_command_spec.rb +46 -0
- data/spec/reek/cli/report_spec.rb +30 -0
- data/spec/reek/{version_command_spec.rb → cli/version_command_spec.rb} +3 -3
- data/spec/reek/cli/yaml_command_spec.rb +47 -0
- data/spec/reek/core/code_context_spec.rb +145 -0
- data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +7 -6
- data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
- data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +16 -36
- data/spec/reek/core/module_context_spec.rb +27 -0
- data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
- data/spec/reek/core/singleton_method_context_spec.rb +9 -0
- data/spec/reek/core/smell_configuration_spec.rb +11 -0
- data/spec/reek/core/stop_context_spec.rb +17 -0
- data/spec/reek/core/warning_collector_spec.rb +27 -0
- data/spec/reek/examiner_spec.rb +103 -0
- data/spec/reek/smell_warning_spec.rb +74 -82
- data/spec/reek/smells/attribute_spec.rb +42 -23
- data/spec/reek/smells/behaves_like_variable_detector.rb +2 -2
- data/spec/reek/smells/boolean_parameter_spec.rb +66 -0
- data/spec/reek/smells/class_variable_spec.rb +60 -75
- data/spec/reek/smells/control_couple_spec.rb +37 -32
- data/spec/reek/smells/data_clump_spec.rb +63 -24
- data/spec/reek/smells/duplication_spec.rb +106 -57
- data/spec/reek/smells/feature_envy_spec.rb +113 -92
- data/spec/reek/smells/irresponsible_module_spec.rb +58 -0
- data/spec/reek/smells/large_class_spec.rb +67 -57
- data/spec/reek/smells/long_method_spec.rb +40 -10
- data/spec/reek/smells/long_parameter_list_spec.rb +50 -28
- data/spec/reek/smells/long_yield_list_spec.rb +57 -0
- data/spec/reek/smells/nested_iterators_spec.rb +115 -7
- data/spec/reek/smells/simulated_polymorphism_spec.rb +56 -20
- data/spec/reek/smells/smell_detector_shared.rb +42 -0
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +42 -0
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +66 -0
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +71 -0
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +120 -0
- data/spec/reek/smells/utility_function_spec.rb +50 -4
- data/spec/reek/source/code_comment_spec.rb +82 -0
- data/spec/reek/source/object_source_spec.rb +20 -0
- data/spec/reek/source/reference_collector_spec.rb +53 -0
- data/spec/reek/{adapters/source_spec.rb → source/source_code_spec.rb} +7 -8
- data/spec/reek/source/tree_dresser_spec.rb +270 -0
- data/spec/reek/spec/should_reek_of_spec.rb +76 -0
- data/spec/reek/spec/should_reek_only_of_spec.rb +89 -0
- data/spec/reek/{adapters → spec}/should_reek_spec.rb +8 -32
- data/spec/samples/all_but_one_masked/clean_one.rb +1 -0
- data/spec/samples/all_but_one_masked/dirty.rb +1 -0
- data/spec/samples/all_but_one_masked/masked.reek +5 -1
- data/spec/samples/clean_due_to_masking/clean_one.rb +1 -0
- data/spec/samples/clean_due_to_masking/clean_three.rb +1 -0
- data/spec/samples/clean_due_to_masking/clean_two.rb +1 -0
- data/spec/samples/clean_due_to_masking/dirty_one.rb +1 -1
- data/spec/samples/clean_due_to_masking/dirty_two.rb +1 -1
- data/spec/samples/clean_due_to_masking/masked.reek +5 -1
- data/spec/samples/config/allow_duplication.reek +3 -0
- data/spec/samples/config/deeper_nested_iterators.reek +3 -0
- data/spec/samples/corrupt_config_file/dirty.rb +1 -1
- data/spec/samples/demo/demo.rb +8 -0
- data/spec/samples/empty_config_file/dirty.rb +2 -1
- data/spec/samples/exceptions.reek +1 -1
- data/spec/samples/inline_config/dirty.rb +16 -0
- data/spec/samples/inline_config/masked.reek +7 -0
- data/spec/samples/mask_some/dirty.rb +8 -0
- data/spec/samples/mask_some/some.reek +8 -0
- data/spec/samples/masked/dirty.rb +2 -1
- data/spec/samples/masked/masked.reek +3 -1
- data/spec/samples/mixed_results/clean_one.rb +1 -0
- data/spec/samples/mixed_results/clean_three.rb +1 -0
- data/spec/samples/mixed_results/clean_two.rb +1 -0
- data/spec/samples/mixed_results/dirty_one.rb +1 -0
- data/spec/samples/mixed_results/dirty_two.rb +1 -0
- data/spec/samples/not_quite_masked/dirty.rb +2 -1
- data/spec/samples/not_quite_masked/masked.reek +1 -1
- data/spec/samples/overrides/masked/dirty.rb +2 -1
- data/spec/samples/overrides/masked/lower.reek +3 -1
- data/spec/samples/three_clean_files/clean_one.rb +1 -0
- data/spec/samples/three_clean_files/clean_three.rb +1 -0
- data/spec/samples/three_clean_files/clean_two.rb +1 -0
- data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
- data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
- data/spec/spec_helper.rb +10 -2
- data/tasks/reek.rake +2 -2
- data/tasks/test.rake +12 -3
- metadata +121 -79
- data/README.rdoc +0 -84
- data/features/profile.feature +0 -34
- data/lib/reek/adapters/application.rb +0 -46
- data/lib/reek/adapters/command_line.rb +0 -77
- data/lib/reek/adapters/config_file.rb +0 -31
- data/lib/reek/adapters/core_extras.rb +0 -64
- data/lib/reek/adapters/rake_task.rb +0 -121
- data/lib/reek/adapters/report.rb +0 -86
- data/lib/reek/adapters/source.rb +0 -72
- data/lib/reek/adapters/spec.rb +0 -133
- data/lib/reek/block_context.rb +0 -62
- data/lib/reek/class_context.rb +0 -41
- data/lib/reek/code_context.rb +0 -68
- data/lib/reek/code_parser.rb +0 -203
- data/lib/reek/configuration.rb +0 -57
- data/lib/reek/detector_stack.rb +0 -37
- data/lib/reek/help_command.rb +0 -14
- data/lib/reek/if_context.rb +0 -18
- data/lib/reek/masking_collection.rb +0 -33
- data/lib/reek/method_context.rb +0 -138
- data/lib/reek/module_context.rb +0 -49
- data/lib/reek/name.rb +0 -57
- data/lib/reek/object_refs.rb +0 -49
- data/lib/reek/reek_command.rb +0 -28
- data/lib/reek/sexp_formatter.rb +0 -10
- data/lib/reek/singleton_method_context.rb +0 -26
- data/lib/reek/smells/uncommunicative_name.rb +0 -84
- data/lib/reek/sniffer.rb +0 -177
- data/lib/reek/stop_context.rb +0 -35
- data/lib/reek/tree_dresser.rb +0 -82
- data/lib/reek/version_command.rb +0 -14
- data/lib/reek/yield_call_context.rb +0 -12
- data/spec/reek/adapters/report_spec.rb +0 -31
- data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
- data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
- data/spec/reek/block_context_spec.rb +0 -65
- data/spec/reek/class_context_spec.rb +0 -161
- data/spec/reek/code_context_spec.rb +0 -182
- data/spec/reek/configuration_spec.rb +0 -12
- data/spec/reek/if_context_spec.rb +0 -17
- data/spec/reek/masking_collection_spec.rb +0 -236
- data/spec/reek/module_context_spec.rb +0 -46
- data/spec/reek/name_spec.rb +0 -37
- data/spec/reek/object_source_spec.rb +0 -23
- data/spec/reek/reek_command_spec.rb +0 -45
- data/spec/reek/singleton_method_context_spec.rb +0 -16
- data/spec/reek/smells/smell_detector_spec.rb +0 -36
- data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
- data/spec/reek/sniffer_spec.rb +0 -11
- data/spec/reek/stop_context_spec.rb +0 -33
- data/spec/reek/tree_dresser_spec.rb +0 -20
|
@@ -1,52 +1,57 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require '
|
|
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', 'control_couple')
|
|
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 ControlCouple do
|
|
8
|
+
before(:each) do
|
|
9
|
+
@source_name = 'lets get married'
|
|
10
|
+
@detector = ControlCouple.new(@source_name)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it_should_behave_like 'SmellDetector'
|
|
14
|
+
|
|
8
15
|
context 'conditional on a parameter' do
|
|
9
16
|
it 'should report a ternary check on a parameter' do
|
|
10
|
-
'def simple(arga) arga ? @ivar : 3 end'
|
|
17
|
+
src = 'def simple(arga) arga ? @ivar : 3 end'
|
|
18
|
+
src.should smell_of(ControlCouple, ControlCouple::PARAMETER_KEY => 'arga')
|
|
11
19
|
end
|
|
12
20
|
it 'should not report a ternary check on an ivar' do
|
|
13
|
-
'def simple(arga) @ivar ? arga : 3 end'
|
|
21
|
+
src = 'def simple(arga) @ivar ? arga : 3 end'
|
|
22
|
+
src.should_not smell_of(ControlCouple)
|
|
14
23
|
end
|
|
15
24
|
it 'should not report a ternary check on a lvar' do
|
|
16
|
-
'def simple(arga) lvar = 27; lvar ? arga : @ivar end'
|
|
25
|
+
src = 'def simple(arga) lvar = 27; lvar ? arga : @ivar end'
|
|
26
|
+
src.should_not smell_of(ControlCouple)
|
|
17
27
|
end
|
|
18
28
|
it 'should spot a couple inside a block' do
|
|
19
|
-
'def blocks(arg) @text.map { |blk| arg ? blk : "#{blk}" } end'
|
|
29
|
+
src = 'def blocks(arg) @text.map { |blk| arg ? blk : "#{blk}" } end'
|
|
30
|
+
src.should smell_of(ControlCouple, ControlCouple::PARAMETER_KEY => 'arg')
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
|
|
23
|
-
context '
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
context 'when a smell is reported' do
|
|
35
|
+
before :each do
|
|
36
|
+
src = <<EOS
|
|
37
|
+
def things(arg)
|
|
38
|
+
@text.map do |blk|
|
|
39
|
+
arg ? blk : "blk"
|
|
40
|
+
end
|
|
41
|
+
puts "hello" if arg
|
|
42
|
+
end
|
|
43
|
+
EOS
|
|
44
|
+
ctx = MethodContext.new(nil, src.to_reek_source.syntax_tree)
|
|
45
|
+
smells = @detector.examine(ctx)
|
|
46
|
+
smells.length.should == 1
|
|
47
|
+
@warning = smells[0]
|
|
36
48
|
end
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
'def fred.cc(arga = false) end'.should reek_of(:ControlCouple, /arga/)
|
|
44
|
-
end
|
|
45
|
-
it 'reports two parameters defaulted to booleans' do
|
|
46
|
-
src = 'def Module.cc(nowt, arga = true, argb = false, &blk) end'
|
|
47
|
-
src.should reek_of(:ControlCouple, /arga/)
|
|
48
|
-
src.should reek_of(:ControlCouple, /argb/)
|
|
49
|
-
end
|
|
50
|
+
it_should_behave_like 'common fields set correctly'
|
|
51
|
+
|
|
52
|
+
it 'has the correct fields' do
|
|
53
|
+
@warning.smell[ControlCouple::PARAMETER_KEY].should == 'arg'
|
|
54
|
+
@warning.lines.should == [3,6]
|
|
50
55
|
end
|
|
51
56
|
end
|
|
52
57
|
end
|
|
@@ -1,32 +1,59 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require '
|
|
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', 'data_clump')
|
|
3
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
|
|
4
4
|
|
|
5
5
|
include Reek::Smells
|
|
6
6
|
|
|
7
7
|
shared_examples_for 'a data clump detector' do
|
|
8
8
|
it 'does not report small parameter sets' do
|
|
9
9
|
src = <<EOS
|
|
10
|
+
# test module
|
|
10
11
|
#{@context} Scrunch
|
|
11
12
|
def first(pa) @field == :sym ? 0 : 3; end
|
|
12
13
|
def second(pa) @field == :sym; end
|
|
13
14
|
def third(pa) pa - pb + @fred; end
|
|
14
15
|
end
|
|
15
16
|
EOS
|
|
16
|
-
|
|
17
|
-
src.should_not reek
|
|
17
|
+
src.should_not smell_of(DataClump)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
context 'with 3 identical pairs' do
|
|
21
|
+
before :each do
|
|
22
|
+
@module_name = 'Scrunch'
|
|
23
|
+
@src = <<EOS
|
|
24
|
+
#{@context} #{@module_name}
|
|
23
25
|
def first(pa, pb) @field == :sym ? 0 : 3; end
|
|
24
26
|
def second(pa, pb) @field == :sym; end
|
|
25
27
|
def third(pa, pb) pa - pb + @fred; end
|
|
26
28
|
end
|
|
27
29
|
EOS
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
ctx = CodeContext.new(nil, @src.to_reek_source.syntax_tree)
|
|
31
|
+
detector = DataClump.new('newt')
|
|
32
|
+
@smells = detector.examine_context(ctx)
|
|
33
|
+
@warning = @smells[0] # SMELL: too cumbersome!
|
|
34
|
+
@yaml = @warning.to_yaml
|
|
35
|
+
end
|
|
36
|
+
it 'records only the one smell' do
|
|
37
|
+
@smells.length.should == 1
|
|
38
|
+
end
|
|
39
|
+
it 'reports all parameters' do
|
|
40
|
+
@smells[0].smell[DataClump::PARAMETERS_KEY].should == ['pa', 'pb']
|
|
41
|
+
end
|
|
42
|
+
it 'reports the number of occurrences' do
|
|
43
|
+
@smells[0].smell[DataClump::OCCURRENCES_KEY].should == 3
|
|
44
|
+
end
|
|
45
|
+
it 'reports all parameters' do
|
|
46
|
+
@smells[0].smell[DataClump::METHODS_KEY].should == ['first', 'second', 'third']
|
|
47
|
+
end
|
|
48
|
+
it 'reports the declaration line numbers' do
|
|
49
|
+
@smells[0].lines.should == [2,3,4]
|
|
50
|
+
end
|
|
51
|
+
it 'reports the correct smell class' do
|
|
52
|
+
@smells[0].smell_class.should == DataClump::SMELL_CLASS
|
|
53
|
+
end
|
|
54
|
+
it 'reports the context fq name' do
|
|
55
|
+
@smells[0].context.should == @module_name
|
|
56
|
+
end
|
|
30
57
|
end
|
|
31
58
|
|
|
32
59
|
it 'reports 3 swapped pairs in a class' do
|
|
@@ -37,8 +64,8 @@ EOS
|
|
|
37
64
|
def tri(pa, pb) pa - pb + @fred; end
|
|
38
65
|
end
|
|
39
66
|
EOS
|
|
40
|
-
|
|
41
|
-
|
|
67
|
+
src.should smell_of(DataClump, {DataClump::OCCURRENCES_KEY => 3,
|
|
68
|
+
DataClump::PARAMETERS_KEY => ['pa', 'pb']})
|
|
42
69
|
end
|
|
43
70
|
|
|
44
71
|
it 'reports 3 identical parameter sets in a class' do
|
|
@@ -49,14 +76,11 @@ EOS
|
|
|
49
76
|
def third(pa, pb, pc) pa - pb + @fred; end
|
|
50
77
|
end
|
|
51
78
|
EOS
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
|
55
|
-
src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
|
|
56
|
-
src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
|
|
79
|
+
src.should smell_of(DataClump, {DataClump::OCCURRENCES_KEY => 3,
|
|
80
|
+
DataClump::PARAMETERS_KEY => ['pa', 'pb', 'pc']})
|
|
57
81
|
end
|
|
58
82
|
|
|
59
|
-
it '
|
|
83
|
+
it 'reports re-ordered identical parameter sets' do
|
|
60
84
|
src = <<EOS
|
|
61
85
|
#{@context} Scrunch
|
|
62
86
|
def first(pb, pa, pc) @field == :sym ? 0 : 3; end
|
|
@@ -64,11 +88,8 @@ EOS
|
|
|
64
88
|
def third(pa, pb, pc) pa - pb + @fred; end
|
|
65
89
|
end
|
|
66
90
|
EOS
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
|
70
|
-
src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
|
|
71
|
-
src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
|
|
91
|
+
src.should smell_of(DataClump, {DataClump::OCCURRENCES_KEY => 3,
|
|
92
|
+
DataClump::PARAMETERS_KEY => ['pa', 'pb', 'pc']})
|
|
72
93
|
end
|
|
73
94
|
|
|
74
95
|
it 'counts only identical parameter sets' do
|
|
@@ -79,12 +100,30 @@ EOS
|
|
|
79
100
|
def fc(name, windowW, windowH) end
|
|
80
101
|
end
|
|
81
102
|
EOS
|
|
103
|
+
src.should_not smell_of(DataClump)
|
|
104
|
+
end
|
|
82
105
|
|
|
83
|
-
|
|
106
|
+
it 'gets a real example right' do
|
|
107
|
+
src = <<EOS
|
|
108
|
+
#{@context} Inline
|
|
109
|
+
def generate(src, options) end
|
|
110
|
+
def c (src, options) end
|
|
111
|
+
def c_singleton (src, options) end
|
|
112
|
+
def c_raw (src, options) end
|
|
113
|
+
def c_raw_singleton (src, options) end
|
|
114
|
+
end
|
|
115
|
+
EOS
|
|
116
|
+
src.should smell_of(DataClump, DataClump::OCCURRENCES_KEY => 5)
|
|
84
117
|
end
|
|
85
118
|
end
|
|
86
119
|
|
|
87
120
|
describe DataClump do
|
|
121
|
+
before(:each) do
|
|
122
|
+
@detector = DataClump.new('newt')
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it_should_behave_like 'SmellDetector'
|
|
126
|
+
|
|
88
127
|
context 'in a class' do
|
|
89
128
|
before :each do
|
|
90
129
|
@context = 'class'
|
|
@@ -1,77 +1,126 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require 'reek
|
|
4
|
-
require 'reek
|
|
5
|
-
require '
|
|
6
|
-
require 'reek/smells/duplication'
|
|
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', 'duplication')
|
|
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')
|
|
7
6
|
|
|
8
7
|
include Reek
|
|
9
8
|
include Reek::Smells
|
|
10
9
|
|
|
11
|
-
describe Duplication
|
|
12
|
-
it 'should report repeated call' do
|
|
13
|
-
'def double_thing() @other.thing + @other.thing end'.should reek_only_of(:Duplication, /@other.thing/)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'should report repeated call to lvar' do
|
|
17
|
-
'def double_thing(other) other[@thing] + other[@thing] end'.should reek_only_of(:Duplication, /other\[@thing\]/)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'should report call parameters' do
|
|
21
|
-
'def double_thing() @other.thing(2,3) + @other.thing(2,3) end'.should reek_only_of(:Duplication, /@other.thing\(2, 3\)/)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'should report nested calls' do
|
|
25
|
-
ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'.sniff
|
|
26
|
-
ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
|
|
27
|
-
ruby.should reek_of(:Duplication, /@other.thing.foo/)
|
|
28
|
-
end
|
|
10
|
+
describe Duplication do
|
|
29
11
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
12
|
+
context 'when a smell is reported' do
|
|
13
|
+
before :each do
|
|
14
|
+
@source_name = 'copy-cat'
|
|
15
|
+
@detector = Duplication.new(@source_name)
|
|
16
|
+
src = <<EOS
|
|
17
|
+
def double_thing(other)
|
|
18
|
+
other[@thing]
|
|
19
|
+
not_the_sam(at = all)
|
|
20
|
+
other[@thing]
|
|
33
21
|
end
|
|
22
|
+
EOS
|
|
23
|
+
ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
|
|
24
|
+
smells = @detector.examine_context(ctx)
|
|
25
|
+
smells.length.should == 1
|
|
26
|
+
@warning = smells[0]
|
|
27
|
+
end
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'def equals(other) other.thing == self.thing end'.should_not reek
|
|
38
|
-
end
|
|
29
|
+
it_should_behave_like 'SmellDetector'
|
|
30
|
+
it_should_behave_like 'common fields set correctly'
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
it 'reports the call' do
|
|
33
|
+
@warning.smell[Duplication::CALL_KEY].should == 'other[@thing]'
|
|
34
|
+
end
|
|
35
|
+
it 'reports the correct lines' do
|
|
36
|
+
@warning.lines.should == [2,4]
|
|
37
|
+
end
|
|
42
38
|
end
|
|
43
|
-
end
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
context "with repeated method calls" do
|
|
41
|
+
it 'reports repeated call' do
|
|
42
|
+
src = 'def double_thing() @other.thing + @other.thing end'
|
|
43
|
+
src.should smell_of(Duplication, Duplication::CALL_KEY => '@other.thing')
|
|
44
|
+
end
|
|
45
|
+
it 'reports repeated call to lvar' do
|
|
46
|
+
src = 'def double_thing(other) other[@thing] + other[@thing] end'
|
|
47
|
+
src.should smell_of(Duplication, Duplication::CALL_KEY => 'other[@thing]')
|
|
48
|
+
end
|
|
49
|
+
it 'reports call parameters' do
|
|
50
|
+
src = 'def double_thing() @other.thing(2,3) + @other.thing(2,3) end'
|
|
51
|
+
src.should smell_of(Duplication, Duplication::CALL_KEY => '@other.thing(2, 3)')
|
|
52
|
+
end
|
|
53
|
+
it 'should report nested calls' do
|
|
54
|
+
src = 'def double_thing() @other.thing.foo + @other.thing.foo end'
|
|
55
|
+
src.should smell_of(Duplication, {Duplication::CALL_KEY => '@other.thing'},
|
|
56
|
+
{Duplication::CALL_KEY => '@other.thing.foo'})
|
|
57
|
+
end
|
|
58
|
+
it 'should ignore calls to new' do
|
|
59
|
+
src = 'def double_thing() @other.new + @other.new end'
|
|
60
|
+
src.should_not smell_of(Duplication)
|
|
61
|
+
end
|
|
49
62
|
end
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
context 'with repeated attribute assignment' do
|
|
65
|
+
it 'reports repeated assignment' do
|
|
66
|
+
src = 'def double_thing(thing) @other[thing] = true; @other[thing] = true; end'
|
|
67
|
+
src.should smell_of(Duplication, Duplication::CALL_KEY => '@other[thing] = true')
|
|
68
|
+
end
|
|
69
|
+
it 'does not report multi-assignments' do
|
|
70
|
+
src = <<EOS
|
|
71
|
+
def _parse ctxt
|
|
72
|
+
ctxt.index, result = @ind, @result
|
|
73
|
+
error, ctxt.index = @err, @err_ind
|
|
74
|
+
end
|
|
75
|
+
EOS
|
|
76
|
+
src.should_not smell_of(Duplication)
|
|
77
|
+
end
|
|
58
78
|
end
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
context "non-repeated method calls" do
|
|
81
|
+
it 'should not report similar calls' do
|
|
82
|
+
src = 'def equals(other) other.thing == self.thing end'
|
|
83
|
+
src.should_not smell_of(Duplication)
|
|
84
|
+
end
|
|
85
|
+
it 'should respect call parameters' do
|
|
86
|
+
src = 'def double_thing() @other.thing(3) + @other.thing(2) end'
|
|
87
|
+
src.should_not smell_of(Duplication)
|
|
88
|
+
end
|
|
63
89
|
end
|
|
64
|
-
end
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
context "allowing up to 3 calls" do
|
|
92
|
+
before :each do
|
|
93
|
+
@config = {Duplication::MAX_ALLOWED_CALLS_KEY => 3}
|
|
94
|
+
end
|
|
95
|
+
it 'does not report double calls' do
|
|
96
|
+
src = 'def double_thing() @other.thing + @other.thing end'
|
|
97
|
+
src.should_not smell_of(Duplication).with_config(@config)
|
|
98
|
+
end
|
|
99
|
+
it 'does not report triple calls' do
|
|
100
|
+
src = 'def double_thing() @other.thing + @other.thing + @other.thing end'
|
|
101
|
+
src.should_not smell_of(Duplication).with_config(@config)
|
|
102
|
+
end
|
|
103
|
+
it 'reports quadruple calls' do
|
|
104
|
+
src = 'def double_thing() @other.thing + @other.thing + @other.thing + @other.thing end'
|
|
105
|
+
src.should smell_of(Duplication, {Duplication::CALL_KEY => '@other.thing', Duplication::OCCURRENCES_KEY => 4}).with_config(@config)
|
|
106
|
+
end
|
|
70
107
|
end
|
|
71
108
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
109
|
+
context "allowing calls to some methods" do
|
|
110
|
+
before :each do
|
|
111
|
+
@config = {Duplication::ALLOW_CALLS_KEY => ['@some.thing',/puts/]}
|
|
112
|
+
end
|
|
113
|
+
it 'does not report calls to some methods' do
|
|
114
|
+
src = 'def double_some_thing() @some.thing + @some.thing end'
|
|
115
|
+
src.should_not smell_of(Duplication).with_config(@config)
|
|
116
|
+
end
|
|
117
|
+
it 'reports calls to other methods' do
|
|
118
|
+
src = 'def double_other_thing() @other.thing + @other.thing end'
|
|
119
|
+
src.should smell_of(Duplication, {Duplication::CALL_KEY => '@other.thing'}).with_config(@config)
|
|
120
|
+
end
|
|
121
|
+
it 'does not report calls to methods specifed with a regular expression' do
|
|
122
|
+
src = 'def double_puts() puts @other.thing; puts @other.thing end'
|
|
123
|
+
src.should smell_of(Duplication, {Duplication::CALL_KEY => '@other.thing'}).with_config(@config)
|
|
124
|
+
end
|
|
76
125
|
end
|
|
77
126
|
end
|
|
@@ -1,34 +1,76 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
require 'reek
|
|
3
|
-
require '
|
|
4
|
-
require 'reek/stop_context'
|
|
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', 'feature_envy')
|
|
3
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'smell_detector_shared')
|
|
5
4
|
|
|
6
5
|
include Reek
|
|
7
6
|
include Reek::Smells
|
|
8
7
|
|
|
9
8
|
describe FeatureEnvy do
|
|
10
|
-
|
|
11
|
-
'
|
|
9
|
+
context 'with no smell' do
|
|
10
|
+
it 'should not report use of self' do
|
|
11
|
+
'def simple() self.to_s + self.to_i end'.should_not reek
|
|
12
|
+
end
|
|
13
|
+
it 'should not report vcall with no argument' do
|
|
14
|
+
'def simple() func; end'.should_not reek
|
|
15
|
+
end
|
|
16
|
+
it 'should not report vcall with argument' do
|
|
17
|
+
'def simple(arga) func(17); end'.should_not reek
|
|
18
|
+
end
|
|
19
|
+
it 'should not report single use' do
|
|
20
|
+
'def no_envy(arga) arga.barg(@item) end'.should_not reek
|
|
21
|
+
end
|
|
22
|
+
it 'should not report return value' do
|
|
23
|
+
'def no_envy(arga) arga.barg(@item); arga end'.should_not reek
|
|
24
|
+
end
|
|
25
|
+
it 'should ignore global variables' do
|
|
26
|
+
'def no_envy() $s2.to_a; $s2[@item] end'.should_not reek
|
|
27
|
+
end
|
|
28
|
+
it 'should not report class methods' do
|
|
29
|
+
'def simple() self.class.new.flatten_merge(self) end'.should_not reek
|
|
30
|
+
end
|
|
31
|
+
it 'should not report single use of an ivar' do
|
|
32
|
+
'def no_envy() @item.to_a end'.should_not reek
|
|
33
|
+
end
|
|
34
|
+
it 'should not report returning an ivar' do
|
|
35
|
+
'def no_envy() @item.to_a; @item end'.should_not reek
|
|
36
|
+
end
|
|
37
|
+
it 'should not report ivar usage in a parameter' do
|
|
38
|
+
'def no_envy() @item.price + tax(@item) - savings(@item) end'.should_not reek
|
|
39
|
+
end
|
|
40
|
+
it 'should not report single use of an lvar' do
|
|
41
|
+
'def no_envy() lv = @item; lv.to_a end'.should_not reek
|
|
42
|
+
end
|
|
43
|
+
it 'should not report returning an lvar' do
|
|
44
|
+
'def no_envy() lv = @item; lv.to_a; lv end'.should_not reek
|
|
45
|
+
end
|
|
46
|
+
it 'ignores lvar usage in a parameter' do
|
|
47
|
+
'def no_envy() lv = @item; lv.price + tax(lv) - savings(lv); end'.should_not reek
|
|
48
|
+
end
|
|
49
|
+
it 'ignores multiple ivars' do
|
|
50
|
+
src = <<EOS
|
|
51
|
+
def func
|
|
52
|
+
@other.a
|
|
53
|
+
@other.b
|
|
54
|
+
@nother.c
|
|
55
|
+
@nother.d
|
|
12
56
|
end
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'should not report return value' do
|
|
27
|
-
'def no_envy(arga) arga.barg(@item); arga end'.should_not reek
|
|
57
|
+
EOS
|
|
58
|
+
src.should_not reek
|
|
59
|
+
#
|
|
60
|
+
# def other.func(me)
|
|
61
|
+
# a
|
|
62
|
+
# b
|
|
63
|
+
# me.nother_c
|
|
64
|
+
# me.nother_d
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
end
|
|
28
68
|
end
|
|
29
69
|
|
|
30
|
-
|
|
31
|
-
'
|
|
70
|
+
context 'with 2 calls to a parameter' do
|
|
71
|
+
it 'reports the smell' do
|
|
72
|
+
'def envy(arga) arga.b(arga) + arga.c(@fred) end'.should reek_only_of(:FeatureEnvy, /arga/)
|
|
73
|
+
end
|
|
32
74
|
end
|
|
33
75
|
|
|
34
76
|
it 'should report highest affinity' do
|
|
@@ -57,26 +99,6 @@ EOS
|
|
|
57
99
|
src.should reek_of(:FeatureEnvy, /fred/)
|
|
58
100
|
end
|
|
59
101
|
|
|
60
|
-
it 'should ignore global variables' do
|
|
61
|
-
'def no_envy() $s2.to_a; $s2[@item] end'.should_not reek
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'should not report class methods' do
|
|
65
|
-
'def simple() self.class.new.flatten_merge(self) end'.should_not reek
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'should not report single use of an ivar' do
|
|
69
|
-
'def no_envy() @item.to_a end'.should_not reek
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it 'should not report returning an ivar' do
|
|
73
|
-
'def no_envy() @item.to_a; @item end'.should_not reek
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it 'should not report ivar usage in a parameter' do
|
|
77
|
-
'def no_envy() @item.price + tax(@item) - savings(@item) end'.should_not reek
|
|
78
|
-
end
|
|
79
|
-
|
|
80
102
|
it 'should not be fooled by duplication' do
|
|
81
103
|
'def feed(thing) @cow.feed_to(thing.pig); @duck.feed_to(thing.pig) end'.should reek_only_of(:Duplication, /thing.pig/)
|
|
82
104
|
end
|
|
@@ -85,14 +107,6 @@ EOS
|
|
|
85
107
|
'def feed(thing) cow.feed_to(thing.pig); duck.feed_to(thing.pig) end'.should reek_only_of(:Duplication, /thing.pig/)
|
|
86
108
|
end
|
|
87
109
|
|
|
88
|
-
it 'should not report single use of an lvar' do
|
|
89
|
-
'def no_envy() lv = @item; lv.to_a end'.should_not reek
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it 'should not report returning an lvar' do
|
|
93
|
-
'def no_envy() lv = @item; lv.to_a; lv end'.should_not reek
|
|
94
|
-
end
|
|
95
|
-
|
|
96
110
|
it 'should report many calls to lvar' do
|
|
97
111
|
'def envy() lv = @item; lv.price + lv.tax; end'.should reek_only_of(:FeatureEnvy, /lv/)
|
|
98
112
|
#
|
|
@@ -105,30 +119,6 @@ EOS
|
|
|
105
119
|
# end
|
|
106
120
|
end
|
|
107
121
|
|
|
108
|
-
it 'ignores lvar usage in a parameter' do
|
|
109
|
-
'def no_envy() lv = @item; lv.price + tax(lv) - savings(lv); end'.should_not reek
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it 'ignores multiple ivars' do
|
|
113
|
-
src = <<EOS
|
|
114
|
-
def func
|
|
115
|
-
@other.a
|
|
116
|
-
@other.b
|
|
117
|
-
@nother.c
|
|
118
|
-
@nother.d
|
|
119
|
-
end
|
|
120
|
-
EOS
|
|
121
|
-
src.should_not reek
|
|
122
|
-
#
|
|
123
|
-
# def other.func(me)
|
|
124
|
-
# a
|
|
125
|
-
# b
|
|
126
|
-
# me.nother_c
|
|
127
|
-
# me.nother_d
|
|
128
|
-
# end
|
|
129
|
-
#
|
|
130
|
-
end
|
|
131
|
-
|
|
132
122
|
it 'ignores frequent use of a call' do
|
|
133
123
|
'def func() other.a; other.b; nother.c end'.should_not reek_of(:FeatureEnvy)
|
|
134
124
|
end
|
|
@@ -166,8 +156,8 @@ EOS
|
|
|
166
156
|
it 'interprets << correctly' do
|
|
167
157
|
ruby = <<EOS
|
|
168
158
|
def report_on(report)
|
|
169
|
-
if @
|
|
170
|
-
report.
|
|
159
|
+
if @is_doubled
|
|
160
|
+
report.record_doubled_smell(self)
|
|
171
161
|
else
|
|
172
162
|
report << self
|
|
173
163
|
end
|
|
@@ -178,20 +168,51 @@ EOS
|
|
|
178
168
|
end
|
|
179
169
|
end
|
|
180
170
|
|
|
181
|
-
describe FeatureEnvy
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
@
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
171
|
+
describe FeatureEnvy do
|
|
172
|
+
before(:each) do
|
|
173
|
+
@source_name = 'green as a cucumber'
|
|
174
|
+
@detector = FeatureEnvy.new(@source_name)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it_should_behave_like 'SmellDetector'
|
|
178
|
+
|
|
179
|
+
context 'when reporting yaml' do
|
|
180
|
+
before :each do
|
|
181
|
+
@receiver = 'other'
|
|
182
|
+
src = <<EOS
|
|
183
|
+
def envious(other)
|
|
184
|
+
#{@receiver}.call
|
|
185
|
+
self.do_nothing
|
|
186
|
+
#{@receiver}.other
|
|
187
|
+
#{@receiver}.fred
|
|
188
|
+
end
|
|
189
|
+
EOS
|
|
190
|
+
source = src.to_reek_source
|
|
191
|
+
sniffer = Sniffer.new(source)
|
|
192
|
+
@mctx = CodeParser.new(sniffer).process_defn(source.syntax_tree)
|
|
193
|
+
@smells = @detector.examine_context(@mctx)
|
|
194
|
+
end
|
|
195
|
+
it 'reports only that smell' do
|
|
196
|
+
@smells.length.should == 1
|
|
197
|
+
end
|
|
198
|
+
it 'reports the source' do
|
|
199
|
+
@smells[0].source.should == @source_name
|
|
200
|
+
end
|
|
201
|
+
it 'reports the class' do
|
|
202
|
+
@smells[0].smell_class.should == FeatureEnvy::SMELL_CLASS
|
|
203
|
+
end
|
|
204
|
+
it 'reports the subclass' do
|
|
205
|
+
@smells[0].subclass.should == FeatureEnvy::SMELL_SUBCLASS
|
|
206
|
+
end
|
|
207
|
+
it 'reports the envious receiver' do
|
|
208
|
+
@smells[0].smell[FeatureEnvy::RECEIVER_KEY].should == @receiver
|
|
209
|
+
end
|
|
210
|
+
it 'reports the number of references' do
|
|
211
|
+
@smells[0].smell[FeatureEnvy::REFERENCES_KEY].should == 3
|
|
212
|
+
end
|
|
213
|
+
it 'reports the referring lines' do
|
|
214
|
+
pending
|
|
215
|
+
@smells[0].lines.should == [2, 4, 5]
|
|
216
|
+
end
|
|
196
217
|
end
|
|
197
218
|
end
|