reek 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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