reek 0.2.2 → 0.2.3

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/lib/reek/version.rb CHANGED
@@ -2,7 +2,7 @@ module Reek #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
3
3
  require 'reek/version'
4
4
 
5
5
  describe 'Reek version number' do
6
- it 'should reprot the correct value' do
6
+ it 'should report the correct value' do
7
7
  actual = `ruby -Ilib bin/reek --version`.split
8
8
  actual[0].should == 'reek'
9
9
  actual[1].should == Reek::VERSION::STRING
@@ -20,6 +20,7 @@ describe 'Integration test:' do
20
20
 
21
21
  it 'should report the correct smells' do
22
22
  actual = `ruby -Ilib bin/reek #{source} 2>/dev/null`.split(/\n/)
23
+ actual.length.should == @expected.length
23
24
  @expected.zip(actual).each do |p|
24
25
  actual = p[1] ? p[1].chomp : p[1]
25
26
  actual.should == p[0]
@@ -28,6 +29,7 @@ describe 'Integration test:' do
28
29
 
29
30
  it 'should report the correct smells in smell order' do
30
31
  actual = `ruby -Ilib bin/reek --sort smell #{source} 2>/dev/null`.split(/\n/)
32
+ actual.length.should == @expected.length
31
33
  @expected.sort.zip(actual).each do |p|
32
34
  actual = p[1] ? p[1].chomp : p[1]
33
35
  actual.should == p[0]
@@ -36,13 +38,3 @@ describe 'Integration test:' do
36
38
  end
37
39
  end
38
40
  end
39
-
40
- describe 'Reek source code:' do
41
- Dir['lib/**/*.rb'].each do |source|
42
- describe source do
43
- it 'should report no smells' do
44
- `ruby -Ilib bin/reek #{source}`.should == "\n"
45
- end
46
- end
47
- end
48
- end
@@ -1,49 +1,87 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
2
 
3
3
  require 'reek/method_checker'
4
+ require 'reek/smells'
4
5
  require 'reek/report'
5
6
 
6
7
  include Reek
7
8
 
8
- describe MethodChecker, "(Feature Envy)" do
9
-
9
+ describe FeatureEnvy, 'with only messages to self' do
10
10
  before(:each) do
11
11
  @rpt = Report.new
12
12
  @cchk = MethodChecker.new(@rpt, 'Thing')
13
13
  end
14
14
 
15
- it 'should not report local method call' do
16
- @cchk.check_source('def simple(arga) f(17) end')
15
+ it 'should not report use of self' do
16
+ @cchk.check_source('def simple() self.to_s + self.to_i end')
17
+ @rpt.should be_empty
18
+ end
19
+
20
+ it 'should not report vcall with no argument' do
21
+ @cchk.check_source('def simple() func + grunc end')
22
+ @rpt.should be_empty
23
+ end
24
+
25
+ it 'should not report vcall with argument' do
26
+ @cchk.check_source('def simple(arga) func(17) + grunc(arga) end')
17
27
  @rpt.should be_empty
18
28
  end
29
+ end
19
30
 
20
- it 'should report message chain' do
21
- @cchk.check_source('def parse(arga) arga.b.c end')
22
- @rpt.length.should == 2
31
+ describe FeatureEnvy, 'when the receiver is a parameter' do
32
+ before(:each) do
33
+ @rpt = Report.new
34
+ @cchk = MethodChecker.new(@rpt, 'Thing')
23
35
  end
24
36
 
25
- it 'should report simple parameter call' do
26
- @cchk.check_source('def simple(arga) arga[3] end')
27
- @rpt.length.should == 2
28
- @rpt[0].should == UtilityFunction.new(@cchk)
29
- @rpt[1].should == FeatureEnvy.new(@cchk, :arga)
37
+ it 'should not report single use' do
38
+ @cchk.check_source('def no_envy(arga) arga.barg(@item) end')
39
+ @rpt.length.should == 0
40
+ end
41
+
42
+ it 'should not report return value' do
43
+ @cchk.check_source('def no_envy(arga) arga.barg(@item); arga end')
44
+ @rpt.length.should == 0
45
+ end
46
+
47
+ it 'should report many calls to parameter' do
48
+ @cchk.check_source('def envy(arga) arga.b(arga) + arga.c(@fred) end')
49
+ @rpt.length.should == 1
50
+ FeatureEnvy.should === @rpt[0]
51
+ @rpt[0].to_s.should match(/arga/)
52
+ end
53
+ end
54
+
55
+ describe FeatureEnvy, 'when there are many possible receivers' do
56
+ before(:each) do
57
+ @rpt = Report.new
58
+ @cchk = MethodChecker.new(@rpt, 'Thing')
30
59
  end
31
60
 
32
61
  it 'should report highest affinity' do
33
- @cchk.check_source('def simple(arga) slim = ""; s1 = ""; s1.to_s; @m = 34; end')
62
+ @cchk.check_source('def total_envy() @total += @item.price; @total += @item.tax; @total *= 1.15 end')
34
63
  @rpt.length.should == 1
35
- @rpt[0].should == FeatureEnvy.new(@cchk, :s1)
64
+ FeatureEnvy.should === @rpt[0]
65
+ @rpt[0].to_s.should match(/@total/)
36
66
  end
37
67
 
38
68
  it 'should report multiple affinities' do
39
- @cchk.check_source('def simple(arga) s1 = ""; s1.to_s; s2 = ""; s2.to_s; @m = 34; end')
69
+ @cchk.check_source('def total_envy() @total += @item.price; @total += @item.tax end')
40
70
  @rpt.length.should == 1
41
- @rpt[0].should == FeatureEnvy.new(@cchk, :s1, :s2)
71
+ @rpt[0].to_s.should match(/@total/)
72
+ @rpt[0].to_s.should match(/@item/)
42
73
  end
74
+ end
43
75
 
44
- it 'should not reference global variables' do
45
- @cchk.check_source('def simple(arga) @s = ""; $s2.to_a; $s2.to_s; end')
46
- @rpt.length.should == 0
76
+ describe FeatureEnvy, 'when the receiver is external' do
77
+ before(:each) do
78
+ @rpt = Report.new
79
+ @cchk = MethodChecker.new(@rpt, 'Thing')
80
+ end
81
+
82
+ it 'should ignore global variables' do
83
+ @cchk.check_source('def no_envy() $s2.to_a; $s2[@item] end')
84
+ @rpt.should be_empty
47
85
  end
48
86
 
49
87
  it 'should not report class methods' do
@@ -52,10 +90,111 @@ describe MethodChecker, "(Feature Envy)" do
52
90
  end
53
91
  end
54
92
 
55
- describe FeatureEnvy, '#report' do
56
- it 'should report the envious host' do
57
- mchk = MethodChecker.new([], 'Class')
58
- smell = FeatureEnvy.new(mchk, [:lvar, :fred])
59
- smell.report.should match(/fred/)
93
+ describe FeatureEnvy, 'when the receiver is an ivar' do
94
+ before(:each) do
95
+ @rpt = Report.new
96
+ @cchk = MethodChecker.new(@rpt, 'Thing')
97
+ end
98
+
99
+ it 'should not report single use of an ivar' do
100
+ @cchk.check_source('def no_envy() @item.to_a end')
101
+ @rpt.length.should == 0
102
+ end
103
+
104
+ it 'should not report returning an ivar' do
105
+ @cchk.check_source('def no_envy() @item.to_a; @item end')
106
+ @rpt.length.should == 0
107
+ end
108
+
109
+ it 'should report many calls to ivar' do
110
+ @cchk.check_source('def envy; @item.price + @item.tax end')
111
+ @rpt.length.should == 1
112
+ FeatureEnvy.should === @rpt[0]
113
+ @rpt[0].to_s.should match(/@item/)
114
+ end
115
+
116
+ it 'should not report ivar usage in a parameter' do
117
+ @cchk.check_source('def no_envy; @item.price + tax(@item) - savings(@item) end')
118
+ @rpt.should be_empty
119
+ end
120
+ end
121
+
122
+ describe FeatureEnvy, 'when the receiver is an lvar' do
123
+ before(:each) do
124
+ @rpt = Report.new
125
+ @cchk = MethodChecker.new(@rpt, 'Thing')
126
+ end
127
+
128
+ it 'should not report single use of an lvar' do
129
+ @cchk.check_source('def no_envy() lv = @item; lv.to_a end')
130
+ @rpt.length.should == 0
131
+ end
132
+
133
+ it 'should not report returning an lvar' do
134
+ @cchk.check_source('def no_envy() lv = @item; lv.to_a; lv end')
135
+ @rpt.length.should == 0
136
+ end
137
+
138
+ it 'should report many calls to lvar' do
139
+ @cchk.check_source('def envy; lv = @item; lv.price + lv.tax end')
140
+ @rpt.length.should == 1
141
+ FeatureEnvy.should === @rpt[0]
142
+ @rpt[0].to_s.should match(/lv/)
143
+ end
144
+
145
+ it 'should not report lvar usage in a parameter' do
146
+ @cchk.check_source('def no_envy; lv = @item; lv.price + tax(lv) - savings(lv) end')
147
+ @rpt.should be_empty
148
+ end
149
+ end
150
+
151
+ describe FeatureEnvy, 'when the receiver is a returned value' do
152
+ before(:each) do
153
+ @rpt = Report.new
154
+ @cchk = MethodChecker.new(@rpt, 'Thing')
155
+ end
156
+
157
+ it 'should not report single use of a return value' do
158
+ @cchk.check_source('def no_envy() f.g.price end')
159
+ @rpt.length.should == 0
160
+ end
161
+
162
+ it 'should not report return value' do
163
+ @cchk.check_source('def no_envy() f.g.wibble; f.g end')
164
+ @rpt.length.should == 1
165
+ FeatureEnvy.should === @rpt[0]
166
+ @rpt[0].to_s.should match(/f/)
167
+ @rpt[0].to_s.should_not match(/f.g/)
168
+ end
169
+
170
+ it 'should report many calls to a returned value' do
171
+ @cchk.check_source('def envy; f.g.price + f.g.tax end')
172
+ @rpt.length.should == 1
173
+ FeatureEnvy.should === @rpt[0]
174
+ @rpt[0].to_s.should match(/f.g/)
175
+ end
176
+
177
+ it 'should not report value usage in a parameter' do
178
+ @cchk.check_source('def no_envy; f.g.price + tax(f.g) - savings(f.g) end')
179
+ @rpt.should be_empty
180
+ end
181
+ end
182
+
183
+ describe FeatureEnvy, 'when the receiver is a dvar' do
184
+ before(:each) do
185
+ @rpt = Report.new
186
+ @cchk = MethodChecker.new(@rpt, 'Thing')
60
187
  end
188
+
189
+ it "should not report method with successive iterators" do
190
+ pending('this is a bug!')
191
+ source =<<EOS
192
+ def bad(fred)
193
+ @fred.each {|item| item.each }
194
+ @jim.each {|item| item.each }
195
+ end
196
+ EOS
197
+ @chk.check_source(source)
198
+ @rpt.should be_empty
199
+ end
61
200
  end
@@ -27,18 +27,18 @@ describe MethodChecker, "(Long Method)" do
27
27
  source =<<EOS
28
28
  def standard_entries(rbconfig)
29
29
  @abc = rbconfig
30
- rubypath = File.join(@abc['bindir'], @abc['ruby_install_name'] + c['EXEEXT'])
31
- major = c['MAJOR'].to_i
32
- minor = c['MINOR'].to_i
33
- teeny = c['TEENY'].to_i
30
+ rubypath = File.join(@abc['bindir'], @abcf['ruby_install_name'] + cff['EXEEXT'])
31
+ major = yyy['MAJOR'].to_i
32
+ minor = zzz['MINOR'].to_i
33
+ teeny = ccc['TEENY'].to_i
34
34
  version = ""
35
35
  if c['rubylibdir']
36
- libruby = "/lib/ruby"
37
- librubyver = "/lib/ruby/"
38
- librubyverarch = "/lib/ruby/"
39
- siteruby = "lib/ruby/version/site_ruby"
40
- siterubyver = siteruby
41
- siterubyverarch = "$siterubyver/['arch']}"
36
+ @libruby = "/lib/ruby"
37
+ @librubyver = "/lib/ruby/"
38
+ @librubyverarch = "/lib/ruby/"
39
+ @siteruby = "lib/ruby/version/site_ruby"
40
+ @siterubyver = siteruby
41
+ @siterubyverarch = "$siterubyver/['arch']}"
42
42
  end
43
43
  end
44
44
  EOS
@@ -59,7 +59,7 @@ describe MethodChecker, "(Long Block)" do
59
59
  src = <<EOS
60
60
  def long(arga)
61
61
  f(3)
62
- 37.each do |xyzero|
62
+ self.each do |xyzero|
63
63
  xyzero = 1
64
64
  xyzero = 2
65
65
  xyzero = 3
@@ -31,3 +31,37 @@ describe MethodChecker, 'when given a C extension' do
31
31
  @cchk.check_object(Enumerable)
32
32
  end
33
33
  end
34
+
35
+ describe MethodChecker, 'when a yield is the receiver' do
36
+ it 'should report no problems' do
37
+ source = 'def values(*args)
38
+ @to_sql += case
39
+ when block_given? then " #{yield.to_sql}"
40
+ else " values (#{args.to_sql})"
41
+ end
42
+ self
43
+ end'
44
+ rpt = Report.new
45
+ chk = MethodChecker.new(rpt, 'Thing')
46
+ chk.check_source(source)
47
+ rpt.should be_empty
48
+ end
49
+ end
50
+
51
+ describe MethodChecker, '#is_override?' do
52
+ it 'should be false for non-override method' do
53
+ MethodChecker.is_override?('String', 'gsub').should == false
54
+ end
55
+
56
+ it 'should be true for overriding method' do
57
+ MethodChecker.is_override?('MethodChecker', 'to_s').should == true
58
+ end
59
+
60
+ it 'should be false for non-existent class' do
61
+ MethodChecker.is_override?('Flibble', 'to_s').should == false
62
+ end
63
+
64
+ it 'should be true for smells' do
65
+ MethodChecker.is_override?('UtilityFunction', 'recognise?').should == true
66
+ end
67
+ end
@@ -21,8 +21,8 @@ describe MethodChecker, " nested iterators" do
21
21
  source =<<EOS
22
22
  def bad(fred)
23
23
  @fred.each {|item| item.each }
24
- @jim.each {|item| item.each }
25
- end
24
+ @jim.each {|ting| ting.each }
25
+ end
26
26
  EOS
27
27
  @chk.check_source(source)
28
28
  @rpt.should be_empty
@@ -31,8 +31,8 @@ EOS
31
31
  it "should report nested iterators only once per method" do
32
32
  source =<<EOS
33
33
  def bad(fred)
34
- @fred.each {|item| item.each {|part| @jim.send} }
35
- @jim.each {|item| item.each {|piece| @fred.send} }
34
+ @fred.each {|item| item.each {|part| @joe.send} }
35
+ @jim.each {|ting| ting.each {|piece| @hal.send} }
36
36
  end
37
37
  EOS
38
38
  @chk.check_source(source)
@@ -0,0 +1,129 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ require 'reek/object_refs'
4
+
5
+ include Reek
6
+
7
+ describe ObjectRefs, 'when empty' do
8
+ before(:each) do
9
+ @refs = ObjectRefs.new
10
+ end
11
+
12
+ it 'should report one ref to self' do
13
+ @refs.refs_to_self.should == 1
14
+ end
15
+ end
16
+
17
+ describe ObjectRefs, 'with no refs to self' do
18
+ before(:each) do
19
+ @refs = ObjectRefs.new
20
+ @refs.record_ref('a')
21
+ @refs.record_ref('b')
22
+ @refs.record_ref('a')
23
+ end
24
+
25
+ it 'should report no refs to self' do
26
+ @refs.refs_to_self.should == 1
27
+ end
28
+
29
+ it 'should report :a as the max' do
30
+ @refs.max_keys.should == ['a']
31
+ end
32
+
33
+ it 'should not report self as the max' do
34
+ @refs.self_is_max?.should == false
35
+ end
36
+ end
37
+
38
+ describe ObjectRefs, 'with one ref to self' do
39
+ before(:each) do
40
+ @refs = ObjectRefs.new
41
+ @refs.record_ref('a')
42
+ @refs.record_ref('b')
43
+ @refs.record_ref('a')
44
+ @refs.record_reference_to_self
45
+ end
46
+
47
+ it 'should report 1 ref to self' do
48
+ @refs.refs_to_self.should == 2
49
+ end
50
+
51
+ it 'should report self among the max' do
52
+ @refs.max_keys.should be_include('a')
53
+ @refs.max_keys.should be_include(Sexp.from_array([:lit, :self]))
54
+ end
55
+
56
+ it 'should report self as the max' do
57
+ @refs.self_is_max?.should == true
58
+ end
59
+ end
60
+
61
+ describe ObjectRefs, 'with many refs to self' do
62
+ before(:each) do
63
+ @refs = ObjectRefs.new
64
+ @refs.record_reference_to_self
65
+ @refs.record_ref('a')
66
+ @refs.record_reference_to_self
67
+ @refs.record_ref('b')
68
+ @refs.record_ref('a')
69
+ @refs.record_reference_to_self
70
+ end
71
+
72
+ it 'should report all refs to self' do
73
+ @refs.refs_to_self.should == 4
74
+ end
75
+
76
+ it 'should report self among the max' do
77
+ @refs.max_keys.should == [Sexp.from_array([:lit, :self])]
78
+ end
79
+
80
+ it 'should report self as the max' do
81
+ @refs.self_is_max?.should == true
82
+ end
83
+ end
84
+
85
+ describe ObjectRefs, 'when self is not the only max' do
86
+ before(:each) do
87
+ @refs = ObjectRefs.new
88
+ @refs.record_ref('a')
89
+ @refs.record_reference_to_self
90
+ @refs.record_ref('b')
91
+ @refs.record_ref('a')
92
+ end
93
+
94
+ it 'should report all refs to self' do
95
+ @refs.refs_to_self.should == 2
96
+ end
97
+
98
+ it 'should report self among the max' do
99
+ @refs.max_keys.should be_include('a')
100
+ @refs.max_keys.should be_include(Sexp.from_array([:lit, :self]))
101
+ end
102
+
103
+ it 'should report self as the max' do
104
+ @refs.self_is_max?.should == true
105
+ end
106
+ end
107
+
108
+ describe ObjectRefs, 'when self is not among the max' do
109
+ before(:each) do
110
+ @refs = ObjectRefs.new
111
+ @refs.record_ref('a')
112
+ @refs.record_ref('b')
113
+ @refs.record_ref('a')
114
+ @refs.record_ref('b')
115
+ end
116
+
117
+ it 'should report all refs to self' do
118
+ @refs.refs_to_self.should == 1
119
+ end
120
+
121
+ it 'should not report self among the max' do
122
+ @refs.max_keys.should be_include('a')
123
+ @refs.max_keys.should be_include('b')
124
+ end
125
+
126
+ it 'should not report self as the max' do
127
+ @refs.self_is_max?.should == false
128
+ end
129
+ end