cuke_sniffer 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cuke_sniffer.rb +8 -23
- data/lib/cuke_sniffer/cli.rb +38 -5
- data/lib/cuke_sniffer/constants.rb +1 -1
- data/lib/cuke_sniffer/cuke_sniffer_helper.rb +1 -1
- data/lib/cuke_sniffer/dead_steps_helper.rb +1 -1
- data/lib/cuke_sniffer/feature.rb +109 -104
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +55 -56
- data/lib/cuke_sniffer/formatter.rb +1 -1
- data/lib/cuke_sniffer/hook.rb +103 -77
- data/lib/cuke_sniffer/report/rules.html.erb +0 -5
- data/lib/cuke_sniffer/rule.rb +26 -27
- data/lib/cuke_sniffer/rule_config.rb +114 -128
- data/lib/cuke_sniffer/rule_target.rb +78 -62
- data/lib/cuke_sniffer/rules_evaluator.rb +52 -64
- data/lib/cuke_sniffer/scenario.rb +123 -102
- data/lib/cuke_sniffer/step_definition.rb +176 -163
- data/lib/cuke_sniffer/summary_helper.rb +1 -1
- data/lib/cuke_sniffer/summary_node.rb +17 -18
- metadata +2 -2
@@ -2,7 +2,7 @@ require 'erb'
|
|
2
2
|
|
3
3
|
module CukeSniffer
|
4
4
|
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
5
|
-
# Copyright:: Copyright (C)
|
5
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
6
6
|
# License:: Distributes under the MIT License
|
7
7
|
# Mixins: CukeSniffer::Constants
|
8
8
|
# Static class used to generate output for the CukeSniffer::CLI object.
|
data/lib/cuke_sniffer/hook.rb
CHANGED
@@ -1,77 +1,103 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
xml_accessor :
|
12
|
-
xml_accessor :
|
13
|
-
xml_accessor :
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
comparison_object.
|
47
|
-
comparison_object.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def
|
55
|
-
@
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
1
|
+
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# Cucumber Hook class used for evaluating rules
|
7
|
+
# Extends CukeSniffer::RulesEvaluator
|
8
|
+
class Hook < RuleTarget
|
9
|
+
|
10
|
+
xml_accessor :start_line
|
11
|
+
xml_accessor :tags, :as => [], :in => "tags"
|
12
|
+
xml_accessor :parameters, :as => [], :in => "parameters"
|
13
|
+
xml_accessor :code, :as => [], :in => "code"
|
14
|
+
|
15
|
+
# The type of the hook: AfterConfiguration, After, AfterStep, Around, Before, at_exit
|
16
|
+
attr_accessor :type
|
17
|
+
|
18
|
+
# The list of tags used as a filter for the hook
|
19
|
+
attr_accessor :tags
|
20
|
+
|
21
|
+
# The parameters that are declared on the hook
|
22
|
+
attr_accessor :parameters
|
23
|
+
|
24
|
+
# Integer of the line in which the hook was found
|
25
|
+
attr_accessor :start_line
|
26
|
+
|
27
|
+
# Array of strings that contain the code kept in the hook
|
28
|
+
attr_accessor :code
|
29
|
+
|
30
|
+
|
31
|
+
# location must be in the format of "file_path\file_name.rb:line_number"
|
32
|
+
# raw_code is an array of strings that represents the step definition
|
33
|
+
# must contain the hook declaration line and the pairing end
|
34
|
+
def initialize(location, hook_block)
|
35
|
+
super(location)
|
36
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
37
|
+
end_match_index = (hook_block.size - 1) - hook_block.reverse.index("end")
|
38
|
+
@code = hook_block[1...end_match_index]
|
39
|
+
initialize_hook_signature(hook_block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def ==(comparison_object) # :nodoc:
|
43
|
+
super(comparison_object) &&
|
44
|
+
comparison_object.type == type &&
|
45
|
+
comparison_object.tags == tags &&
|
46
|
+
comparison_object.parameters == parameters &&
|
47
|
+
comparison_object.code == code
|
48
|
+
end
|
49
|
+
|
50
|
+
def around?
|
51
|
+
type == 'Around'
|
52
|
+
end
|
53
|
+
|
54
|
+
def calls_block?
|
55
|
+
@code.join.to_s.include?("#{@parameters[1]}.call")
|
56
|
+
end
|
57
|
+
|
58
|
+
def conflicting_tags?
|
59
|
+
all_tags = get_indepentent_tags
|
60
|
+
all_tags.each do |single_tag|
|
61
|
+
tag = single_tag.gsub("~", "")
|
62
|
+
return true if all_tags.include?(tag) and all_tags.include?("~#{tag}")
|
63
|
+
end
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def rescues?
|
68
|
+
@code.empty? or @code.join.to_s =~ /.*begin.*rescue.*/
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def get_indepentent_tags
|
74
|
+
all_tags = []
|
75
|
+
@tags.each { |single_tag| all_tags << single_tag.split(',') }
|
76
|
+
all_tags.flatten!
|
77
|
+
all_tags
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize_hook_signature(hook_block)
|
81
|
+
@type = nil
|
82
|
+
@tags = []
|
83
|
+
@parameters = []
|
84
|
+
|
85
|
+
hook_signature = extract_hook_signature(hook_block)
|
86
|
+
matches = HOOK_REGEX.match(hook_signature)
|
87
|
+
@type = matches[:type]
|
88
|
+
initialize_tags(matches[:tags]) if matches[:tags]
|
89
|
+
@parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_hook_signature(hook_block)
|
93
|
+
hook_block.each do |line|
|
94
|
+
return line if line =~ HOOK_REGEX
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def initialize_tags(tag_list)
|
99
|
+
hook_tag_regexp = /["']([^"']*)["']/
|
100
|
+
tag_list.scan(hook_tag_regexp).each { |tag| @tags << tag[0] }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/cuke_sniffer/rule.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
xml_accessor :
|
12
|
-
xml_accessor :
|
13
|
-
xml_accessor :
|
14
|
-
xml_accessor :
|
15
|
-
xml_accessor :
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
1
|
+
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# Single Rule object used for passing around rule data and serializing out to xml
|
7
|
+
# Mixins: ROXML
|
8
|
+
class Rule
|
9
|
+
include ROXML
|
10
|
+
xml_accessor :enabled
|
11
|
+
xml_accessor :phrase
|
12
|
+
xml_accessor :score
|
13
|
+
xml_accessor :conditions, :as => {:key => "name", :value => "value"}, :in => "conditions", :from => "condition"
|
14
|
+
xml_accessor :targets, :in => "targets"
|
15
|
+
xml_accessor :reason
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@enabled = false
|
19
|
+
@phrase = ""
|
20
|
+
@score = 0
|
21
|
+
@conditions = {}
|
22
|
+
@targets = []
|
23
|
+
@reason = ""
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
28
27
|
end
|
@@ -21,54 +21,54 @@ module CukeSniffer
|
|
21
21
|
:phrase => "Scenario Outline with no examples.",
|
22
22
|
:score => FATAL,
|
23
23
|
:targets => ["Scenario"],
|
24
|
-
:reason =>
|
24
|
+
:reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.size == 1}
|
25
25
|
},
|
26
26
|
:no_examples_table => {
|
27
27
|
:enabled => true,
|
28
28
|
:phrase => "Scenario Outline with no examples table.",
|
29
29
|
:score => FATAL,
|
30
30
|
:targets => ["Scenario"],
|
31
|
-
:reason =>
|
31
|
+
:reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.empty?}
|
32
32
|
},
|
33
33
|
:recursive_nested_step => {
|
34
34
|
:enabled => true,
|
35
35
|
:phrase => "Recursive nested step call.",
|
36
36
|
:score => FATAL,
|
37
37
|
:targets => ["StepDefinition"],
|
38
|
-
:reason =>
|
38
|
+
:reason => lambda { |step_definition, rule| step_definition.store_rule_many_times(rule, step_definition.recursive_nested_steps.size)}
|
39
39
|
},
|
40
40
|
:background_with_tag => {
|
41
41
|
:enabled => true,
|
42
42
|
:phrase => "There is a background with a tag. This feature file cannot run!",
|
43
43
|
:score => FATAL,
|
44
44
|
:targets => ["Background"],
|
45
|
-
:reason =>
|
45
|
+
:reason => lambda { |background, rule| background.tags.size > 0}
|
46
46
|
},
|
47
47
|
:comment_after_tag => {
|
48
48
|
:enabled => true,
|
49
49
|
:phrase => "Comment comes between tag and properly executing line. This feature file cannot run!",
|
50
50
|
:score => FATAL,
|
51
51
|
:targets => ["Feature", "Scenario"],
|
52
|
-
:reason =>
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
:reason =>
|
53
|
+
lambda { |feature_rule_target, rule|
|
54
|
+
tokens = feature_rule_target.tags.collect { |line| line.split }.flatten
|
55
|
+
|
56
|
+
tokens.each_with_index do |token, index|
|
57
|
+
if feature_rule_target.is_comment?(token) && tokens[0...index].any? { |x| x =~ /\A@/ }
|
58
|
+
return feature_rule_target.store_rule(rule)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
}
|
62
62
|
},
|
63
63
|
:universal_nested_step => {
|
64
64
|
:enabled => true,
|
65
65
|
:phrase => "A nested step should not universally match all step definitions. Dead steps cannot be correctly cataloged.",
|
66
66
|
:score => FATAL,
|
67
67
|
:targets => ["StepDefinition"],
|
68
|
-
:reason =>
|
69
|
-
modified_step = step_value.gsub(
|
70
|
-
store_rule(
|
71
|
-
end
|
68
|
+
:reason => lambda { |step_definition, rule| step_definition.nested_steps.each_value do | step_value |
|
69
|
+
modified_step = step_value.gsub(/\#{[^}]*}/, '.*')
|
70
|
+
step_definition.store_rule(rule) if modified_step == '.*'
|
71
|
+
end}
|
72
72
|
}
|
73
73
|
}
|
74
74
|
|
@@ -78,83 +78,72 @@ module CukeSniffer
|
|
78
78
|
:phrase => "{class} has no description.",
|
79
79
|
:score => ERROR,
|
80
80
|
:targets => ["Feature", "Scenario"],
|
81
|
-
:reason =>
|
81
|
+
:reason => lambda { |feature_rule_target, rule| feature_rule_target.name.empty?}
|
82
82
|
},
|
83
83
|
:no_scenarios => {
|
84
84
|
:enabled => true,
|
85
85
|
:phrase => "Feature with no scenarios.",
|
86
86
|
:score => ERROR,
|
87
87
|
:targets => ["Feature"],
|
88
|
-
:reason =>
|
88
|
+
:reason => lambda { |feature, rule| feature.scenarios.empty?}
|
89
89
|
},
|
90
90
|
:commented_step => {
|
91
91
|
:enabled => true,
|
92
92
|
:phrase => "Commented step.",
|
93
93
|
:score => ERROR,
|
94
94
|
:targets => ["Scenario", "Background"],
|
95
|
-
:reason =>
|
96
|
-
store_rule(
|
97
|
-
end
|
95
|
+
:reason => lambda { |scenario, rule| scenario.steps.each do |step|
|
96
|
+
scenario.store_rule(rule) if scenario.is_comment?(step)
|
97
|
+
end}
|
98
98
|
},
|
99
99
|
:commented_example => {
|
100
100
|
:enabled => true,
|
101
101
|
:phrase => "Commented example.",
|
102
102
|
:score => ERROR,
|
103
103
|
:targets => ["Scenario"],
|
104
|
-
:reason =>
|
105
|
-
object.examples_table.each {|example| store_rule(object, rule) if is_comment?(example)}
|
106
|
-
end"
|
104
|
+
:reason => lambda { |scenario, rule| scenario.store_rule_many_times(rule, scenario.commented_examples.size) }
|
107
105
|
},
|
108
106
|
:no_steps => {
|
109
107
|
:enabled => true,
|
110
108
|
:phrase => "No steps in Scenario.",
|
111
109
|
:score => ERROR,
|
112
110
|
:targets => ["Scenario", "Background"],
|
113
|
-
:reason =>
|
111
|
+
:reason => lambda { |scenario, rule| scenario.steps.empty?}
|
114
112
|
},
|
115
113
|
:one_word_step => {
|
116
114
|
:enabled => true,
|
117
115
|
:phrase => "Step that is only one word long.",
|
118
116
|
:score => ERROR,
|
119
117
|
:targets => ["Scenario", "Background"],
|
120
|
-
:reason =>
|
118
|
+
:reason => lambda { |scenario, rule| scenario.steps.each {|step| scenario.store_rule(rule) if step.split.count == 2}}
|
121
119
|
},
|
122
120
|
:no_code => {
|
123
121
|
:enabled => true,
|
124
122
|
:phrase => "No code in Step Definition.",
|
125
123
|
:score => ERROR,
|
126
124
|
:targets => ["StepDefinition"],
|
127
|
-
:reason =>
|
125
|
+
:reason => lambda { |step_definition, rule| step_definition.code.empty?}
|
128
126
|
},
|
129
127
|
:around_hook_without_2_parameters => {
|
130
128
|
:enabled => true,
|
131
129
|
:phrase => "Around hook without 2 parameters for Scenario and Block.",
|
132
130
|
:score => ERROR,
|
133
131
|
:targets => ["Hook"],
|
134
|
-
:reason =>
|
132
|
+
:reason => lambda { |hook, rule| hook.around? and hook.parameters.count != 2}
|
135
133
|
},
|
136
134
|
:around_hook_no_block_call => {
|
137
135
|
:enabled => true,
|
138
136
|
:phrase => "Around hook does not call its block.",
|
139
137
|
:score => ERROR,
|
140
138
|
:targets => ["Hook"],
|
141
|
-
:reason =>
|
142
|
-
flag = false if object.type != 'Around'
|
143
|
-
block_call = \"\#{object.parameters[1]}.call\"
|
144
|
-
object.code.each do |line|
|
145
|
-
if line.include?(block_call)
|
146
|
-
flag = false
|
147
|
-
break
|
148
|
-
end
|
149
|
-
end
|
150
|
-
flag"
|
139
|
+
:reason => lambda { |hook, rule| hook.around? and !hook.calls_block?}
|
151
140
|
},
|
152
141
|
:hook_no_debugging => {
|
153
142
|
:enabled => true,
|
154
143
|
:phrase => "Hook without a begin/rescue. Reduced visibility when debugging.",
|
155
144
|
:score => ERROR,
|
156
145
|
:targets => ["Hook"],
|
157
|
-
:reason =>
|
146
|
+
:reason => lambda { |hook, rule| !hook.rescues?}
|
158
147
|
|
159
148
|
},
|
160
149
|
:hook_conflicting_tags => {
|
@@ -162,19 +151,7 @@ module CukeSniffer
|
|
162
151
|
:phrase => "Hook that both expects and ignores the same tag. This hook will not function as expected.",
|
163
152
|
:score => ERROR,
|
164
153
|
:targets => ["Hook"],
|
165
|
-
:reason =>
|
166
|
-
object.tags.each { |single_tag| all_tags << single_tag.split(',') }
|
167
|
-
all_tags.flatten!
|
168
|
-
flag = false
|
169
|
-
all_tags.each do |single_tag|
|
170
|
-
tag = single_tag.gsub(\"~\", \"\")
|
171
|
-
if all_tags.include?(tag) and all_tags.include?(\"~\#{tag}\")
|
172
|
-
flag = true
|
173
|
-
break
|
174
|
-
end
|
175
|
-
end
|
176
|
-
flag
|
177
|
-
"
|
154
|
+
:reason => lambda { |hook, rule| hook.conflicting_tags? }
|
178
155
|
},
|
179
156
|
}
|
180
157
|
|
@@ -184,28 +161,28 @@ module CukeSniffer
|
|
184
161
|
:phrase => "{class} has numbers in the description.",
|
185
162
|
:score => WARNING,
|
186
163
|
:targets => ["Feature", "Scenario", "Background"],
|
187
|
-
:reason =>
|
164
|
+
:reason => lambda { |feature_rule_target, rule| !(feature_rule_target.name =~ /\d+/).nil?}
|
188
165
|
},
|
189
166
|
:empty_feature => {
|
190
167
|
:enabled => true,
|
191
168
|
:phrase => "Feature file has no content.",
|
192
169
|
:score => WARNING,
|
193
170
|
:targets => ["Feature"],
|
194
|
-
:reason =>
|
171
|
+
:reason => lambda { |feature, rule| feature.feature_lines == []}
|
195
172
|
},
|
196
173
|
:background_with_no_scenarios => {
|
197
174
|
:enabled => true,
|
198
175
|
:phrase => "Feature has a background with no scenarios.",
|
199
176
|
:score => WARNING,
|
200
177
|
:targets => ["Feature"],
|
201
|
-
:reason =>
|
178
|
+
:reason => lambda { |feature, rule| feature.scenarios.empty? and !feature.background.nil?}
|
202
179
|
},
|
203
180
|
:background_with_one_scenario => {
|
204
181
|
:enabled => true,
|
205
182
|
:phrase => "Feature has a background with one scenario.",
|
206
183
|
:score => WARNING,
|
207
184
|
:targets => ["Feature"],
|
208
|
-
:reason =>
|
185
|
+
:reason => lambda { |feature, rule| feature.scenarios.size == 1 and !feature.background.nil?}
|
209
186
|
},
|
210
187
|
:too_many_steps => {
|
211
188
|
:enabled => true,
|
@@ -213,18 +190,18 @@ module CukeSniffer
|
|
213
190
|
:score => WARNING,
|
214
191
|
:max => 7,
|
215
192
|
:targets => ["Scenario", "Background"],
|
216
|
-
:reason =>
|
193
|
+
:reason => lambda { |scenario, rule| scenario.steps.count > rule.conditions[:max]}
|
217
194
|
},
|
218
195
|
:out_of_order_steps => {
|
219
196
|
:enabled => true,
|
220
197
|
:phrase => "Scenario steps out of Given/When/Then order.",
|
221
198
|
:score => WARNING,
|
222
199
|
:targets => ["Scenario"],
|
223
|
-
:reason =>
|
200
|
+
:reason => lambda { |scenario, rule| step_order = scenario.get_step_order
|
224
201
|
["But", "*", "And"].each { |type| step_order.delete(type) }
|
225
202
|
if(step_order != %w(Given When Then) and step_order != %w(When Then))
|
226
|
-
store_rule(
|
227
|
-
end
|
203
|
+
scenario.store_rule(rule)
|
204
|
+
end}
|
228
205
|
|
229
206
|
},
|
230
207
|
:invalid_first_step => {
|
@@ -232,24 +209,22 @@ module CukeSniffer
|
|
232
209
|
:phrase => "Invalid first step. Began with And/But.",
|
233
210
|
:score => WARNING,
|
234
211
|
:targets => ["Scenario", "Background"],
|
235
|
-
:reason =>
|
212
|
+
:reason => lambda { |scenario, rule| !(scenario.steps.first =~ /^\s*(And|But).*$/).nil?}
|
236
213
|
},
|
237
214
|
:asterisk_step => {
|
238
215
|
:enabled => true,
|
239
216
|
:phrase => "Step includes a * instead of Given/When/Then/And/But.",
|
240
217
|
:score => WARNING,
|
241
218
|
:targets => ["Scenario", "Background"],
|
242
|
-
:reason =>
|
243
|
-
|
244
|
-
end
|
245
|
-
"
|
219
|
+
:reason => lambda { |scenario, rule| scenario.store_rule_many_times(rule, scenario.get_steps("*").size)
|
220
|
+
}
|
246
221
|
},
|
247
222
|
:one_example => {
|
248
223
|
:enabled => true,
|
249
224
|
:phrase => "Scenario Outline with only one example.",
|
250
225
|
:score => WARNING,
|
251
226
|
:targets => ["Scenario"],
|
252
|
-
:reason =>
|
227
|
+
:reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.size == 2}
|
253
228
|
},
|
254
229
|
:too_many_examples => {
|
255
230
|
:enabled => true,
|
@@ -257,17 +232,18 @@ module CukeSniffer
|
|
257
232
|
:score => WARNING,
|
258
233
|
:max => 10,
|
259
234
|
:targets => ["Scenario"],
|
260
|
-
:reason =>
|
235
|
+
:reason => lambda { |scenario, rule| scenario.outline? and (scenario.examples_table.size - 1) >= rule.conditions[:max]}
|
261
236
|
},
|
262
237
|
:multiple_given_when_then => {
|
263
238
|
:enabled => true,
|
264
239
|
:phrase => "Given/When/Then used multiple times in the same {class}.",
|
265
240
|
:score => WARNING,
|
266
241
|
:targets => ["Scenario", "Background"],
|
267
|
-
:reason =>
|
268
|
-
|
269
|
-
|
270
|
-
|
242
|
+
:reason => lambda { |scenario, rule|
|
243
|
+
phrase = rule.phrase.gsub('{class}', scenario.type)
|
244
|
+
['Given', 'When', 'Then'].each do |step_start|
|
245
|
+
scenario.store_rule(rule, phrase) if scenario.get_steps(step_start).size > 1
|
246
|
+
end}
|
271
247
|
},
|
272
248
|
:too_many_parameters => {
|
273
249
|
:enabled => true,
|
@@ -275,7 +251,7 @@ module CukeSniffer
|
|
275
251
|
:score => WARNING,
|
276
252
|
:max => 4,
|
277
253
|
:targets => ["StepDefinition"],
|
278
|
-
:reason =>
|
254
|
+
:reason => lambda { |step_definition, rule| step_definition.parameters.size > rule.conditions[:max]}
|
279
255
|
|
280
256
|
},
|
281
257
|
:lazy_debugging => {
|
@@ -283,32 +259,32 @@ module CukeSniffer
|
|
283
259
|
:phrase => "Lazy Debugging through puts, p, or print",
|
284
260
|
:score => WARNING,
|
285
261
|
:targets => ["StepDefinition"],
|
286
|
-
:reason =>
|
262
|
+
:reason => lambda { |step_definition, rule| step_definition.code.each {|line| step_definition.store_rule(rule) if line.strip =~ /^(p|puts)( |\()('|"|%(q|Q)?\{)/}}
|
287
263
|
},
|
288
264
|
:pending => {
|
289
265
|
:enabled => true,
|
290
266
|
:phrase => "Pending step definition. Implement or remove.",
|
291
267
|
:score => WARNING,
|
292
268
|
:targets => ["StepDefinition"],
|
293
|
-
:reason =>
|
294
|
-
if line =~
|
295
|
-
store_rule(
|
269
|
+
:reason => lambda { |step_definition, rule| step_definition.code.each {|line|
|
270
|
+
if line =~ /^\s*pending(\(.*\))?(\s*[#].*)?$/
|
271
|
+
step_definition.store_rule(rule)
|
296
272
|
break
|
297
273
|
end
|
298
|
-
}
|
274
|
+
}}
|
299
275
|
},
|
300
276
|
:feature_same_tag => {
|
301
277
|
:enabled => true,
|
302
278
|
:phrase => "Same tag appears on Feature.",
|
303
279
|
:score => WARNING,
|
304
280
|
:targets => ["Feature"],
|
305
|
-
:reason =>
|
306
|
-
|
307
|
-
|
308
|
-
store_rule(
|
281
|
+
:reason => lambda { |feature, rule| if(feature.scenarios.count >= 2)
|
282
|
+
feature.scenarios[1..-1].each do |scenario|
|
283
|
+
feature.scenarios.first.tags.each do |tag|
|
284
|
+
feature.store_rule(rule) if scenario.tags.include?(tag)
|
309
285
|
end
|
310
286
|
end
|
311
|
-
end
|
287
|
+
end}
|
312
288
|
},
|
313
289
|
:scenario_same_tag => {
|
314
290
|
:enabled => true,
|
@@ -316,60 +292,61 @@ module CukeSniffer
|
|
316
292
|
:score => WARNING,
|
317
293
|
:targets => ["Feature"],
|
318
294
|
#TODO really hacky
|
319
|
-
:reason =>
|
320
|
-
base_tag_list =
|
321
|
-
|
295
|
+
:reason => lambda { |feature, rule| unless feature.scenarios.empty?
|
296
|
+
base_tag_list = feature.scenarios.first.tags.clone
|
297
|
+
feature.scenarios.each do |scenario|
|
322
298
|
base_tag_list.each do |tag|
|
323
299
|
base_tag_list.delete(tag) unless scenario.tags.include?(tag)
|
324
300
|
end
|
325
301
|
end
|
326
|
-
base_tag_list.count.times { store_rule(
|
327
|
-
end
|
302
|
+
base_tag_list.count.times { feature.store_rule(rule) }
|
303
|
+
end}
|
328
304
|
},
|
329
305
|
:commas_in_description => {
|
330
306
|
:enabled => true,
|
331
307
|
:phrase => "There are commas in the description, creating possible multirunning scenarios or features.",
|
332
308
|
:score => WARNING,
|
333
309
|
:targets => ["Feature", "Scenario"],
|
334
|
-
:reason =>
|
310
|
+
:reason => lambda { |rule_target, rule| rule_target.name.include?(",")}
|
335
311
|
},
|
336
312
|
:commented_tag => {
|
337
313
|
:enabled => true,
|
338
314
|
:phrase => "{class} has a commented out tag",
|
339
315
|
:score => WARNING,
|
340
316
|
:targets => ["Feature", "Scenario"],
|
341
|
-
:reason =>
|
342
|
-
store_rule(
|
343
|
-
end
|
317
|
+
:reason => lambda { |feature_rule_target, rule| feature_rule_target.tags.each do | tag |
|
318
|
+
feature_rule_target.store_rule(rule, rule.phrase.gsub("{class}", feature_rule_target.type)) if feature_rule_target.is_comment?(tag)
|
319
|
+
end}
|
344
320
|
},
|
345
321
|
:empty_hook => {
|
346
322
|
:enabled => true,
|
347
323
|
:phrase => "Hook with no content.",
|
348
324
|
:score => WARNING,
|
349
325
|
:targets => ["Hook"],
|
350
|
-
:reason =>
|
326
|
+
:reason => lambda { |hook, rule| hook.code == []}
|
351
327
|
},
|
352
328
|
:hook_all_comments => {
|
353
329
|
:enabled => true,
|
354
330
|
:phrase => "Hook is only comments.",
|
355
331
|
:score => WARNING,
|
356
332
|
:targets => ["Hook"],
|
357
|
-
:reason =>
|
358
|
-
|
359
|
-
flag = false if line.match(
|
333
|
+
:reason => lambda { |hook, rule| flag = true
|
334
|
+
hook.code.each do |line|
|
335
|
+
flag = false if line.match(/^\s*#.*$/).nil?
|
360
336
|
end
|
361
|
-
flag
|
337
|
+
flag}
|
362
338
|
},
|
363
339
|
:hook_duplicate_tags => {
|
364
340
|
:enabled => true,
|
365
341
|
:phrase => "Hook has duplicate tags.",
|
366
342
|
:score => WARNING,
|
367
343
|
:targets => ["Hook"],
|
368
|
-
:reason =>
|
369
|
-
|
344
|
+
:reason => lambda { |hook, rule|
|
345
|
+
all_tags = []
|
346
|
+
hook.tags.each { |single_tag| all_tags << single_tag.split(',') }
|
370
347
|
all_tags.flatten!
|
371
348
|
unique_tags = all_tags.uniq
|
372
|
-
true unless all_tags == unique_tags
|
349
|
+
true unless all_tags == unique_tags}
|
373
350
|
}
|
374
351
|
}
|
375
352
|
|
@@ -380,7 +357,7 @@ module CukeSniffer
|
|
380
357
|
:score => INFO,
|
381
358
|
:max => 8,
|
382
359
|
:targets => ["Feature", "Scenario"],
|
383
|
-
:reason =>
|
360
|
+
:reason => lambda { |feature_rule_target, rule| feature_rule_target.tags.size >= rule.conditions[:max]}
|
384
361
|
},
|
385
362
|
:long_name => {
|
386
363
|
:enabled => true,
|
@@ -388,21 +365,21 @@ module CukeSniffer
|
|
388
365
|
:score => INFO,
|
389
366
|
:max => 180,
|
390
367
|
:targets => ["Feature", "Scenario", "Background"],
|
391
|
-
:reason =>
|
368
|
+
:reason => lambda { |feature_rule_target, rule| feature_rule_target.name.length >= rule.conditions[:max]}
|
392
369
|
},
|
393
370
|
:implementation_word => {
|
394
371
|
:enabled => true,
|
395
372
|
:phrase => "Implementation word used: {word}.",
|
396
373
|
:score => INFO,
|
397
|
-
:words => ["page", "site", "url", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen", "
|
374
|
+
:words => ["page", "site", "url", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen", "database", "DB"],
|
398
375
|
:targets => ["Scenario", "Background"],
|
399
|
-
:reason =>
|
400
|
-
next if is_comment?(step)
|
376
|
+
:reason => lambda { |scenario, rule| scenario.steps.each do |step|
|
377
|
+
next if scenario.is_comment?(step)
|
401
378
|
rule.conditions[:words].each do |word|
|
402
379
|
new_phrase = rule.phrase.gsub(/{.*}/, word)
|
403
|
-
store_rule(
|
380
|
+
scenario.store_rule(rule, new_phrase) if step.include?(word)
|
404
381
|
end
|
405
|
-
end
|
382
|
+
end}
|
406
383
|
|
407
384
|
},
|
408
385
|
:implementation_word_button => {
|
@@ -410,41 +387,51 @@ module CukeSniffer
|
|
410
387
|
:phrase => "Implementation word used: button.",
|
411
388
|
:score => INFO,
|
412
389
|
:targets => ["Scenario"],
|
413
|
-
:reason =>
|
414
|
-
matches = step.match(/(?<prefix
|
390
|
+
:reason => lambda { |scenario, rule| scenario.steps.each do |step|
|
391
|
+
matches = step.match(/(?<prefix>\w+)\sbutton/i)
|
415
392
|
if(!matches.nil? and matches[:prefix].downcase != 'radio')
|
416
|
-
store_rule(
|
393
|
+
scenario.store_rule(rule)
|
417
394
|
end
|
418
|
-
end
|
395
|
+
end}
|
419
396
|
|
420
|
-
}
|
397
|
+
},
|
398
|
+
:implementation_word_tab => {
|
399
|
+
:enabled => true,
|
400
|
+
:phrase => "Implementation word used: tab.",
|
401
|
+
:score => INFO,
|
402
|
+
:targets => ["Scenario"],
|
403
|
+
:reason => lambda { |scenario, rule| scenario.steps.each do |step|
|
404
|
+
scenario.store_rule(rule) if (step.split.include?("tab"))
|
405
|
+
end}
|
406
|
+
},
|
407
|
+
:too_many_scenarios => {
|
421
408
|
:enabled => true,
|
422
409
|
:phrase => "Feature with too many scenarios.",
|
423
410
|
:score => INFO,
|
424
411
|
:max => 10,
|
425
412
|
:targets => ["Feature"],
|
426
|
-
:reason =>
|
413
|
+
:reason => lambda { |feature, rule| feature.scenarios.size >= rule.conditions[:max]}
|
427
414
|
},
|
428
415
|
:date_used => {
|
429
416
|
:enabled => true,
|
430
417
|
:phrase => "Date used.",
|
431
418
|
:score => INFO,
|
432
419
|
:targets => ["Scenario", "Background"],
|
433
|
-
:reason =>
|
420
|
+
:reason => lambda { |scenario, rule| scenario.steps.each {|step| scenario.store_rule(rule) if step =~ CukeSniffer::Constants::DATE_REGEX}}
|
434
421
|
},
|
435
422
|
:nested_step => {
|
436
423
|
:enabled => true,
|
437
424
|
:phrase => "Nested step call.",
|
438
425
|
:score => INFO,
|
439
426
|
:targets => ["StepDefinition"],
|
440
|
-
:reason =>
|
427
|
+
:reason => lambda { |step_definition, rule| !step_definition.nested_steps.empty?}
|
441
428
|
},
|
442
429
|
:commented_code => {
|
443
430
|
:enabled => true,
|
444
431
|
:phrase => "Commented code in Step Definition.",
|
445
432
|
:score => INFO,
|
446
433
|
:targets => ["StepDefinition"],
|
447
|
-
:reason =>
|
434
|
+
:reason => lambda { |step_definition, rule| step_definition.code.each {|line| step_definition.store_rule(rule) if step_definition.is_comment?(line)}}
|
448
435
|
},
|
449
436
|
:small_sleep => {
|
450
437
|
:enabled => true,
|
@@ -452,13 +439,13 @@ module CukeSniffer
|
|
452
439
|
:score => INFO,
|
453
440
|
:max => 2,
|
454
441
|
:targets => ["StepDefinition"],
|
455
|
-
:reason =>
|
456
|
-
match_data = line.match
|
442
|
+
:reason => lambda { |step_definition, rule| step_definition.code.each do |line|
|
443
|
+
match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
|
457
444
|
if match_data
|
458
445
|
sleep_value = match_data[:sleep_time].to_f
|
459
|
-
store_rule(
|
446
|
+
step_definition.store_rule(rule) if sleep_value < rule.conditions[:max]
|
460
447
|
end
|
461
|
-
end
|
448
|
+
end}
|
462
449
|
},
|
463
450
|
:large_sleep => {
|
464
451
|
:enabled => true,
|
@@ -466,21 +453,20 @@ module CukeSniffer
|
|
466
453
|
:score => INFO,
|
467
454
|
:min => 2,
|
468
455
|
:targets => ["StepDefinition"],
|
469
|
-
:reason =>
|
470
|
-
match_data = line.match
|
456
|
+
:reason => lambda { |step_definition, rule| step_definition.code.each do |line|
|
457
|
+
match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
|
471
458
|
if match_data
|
472
459
|
sleep_value = match_data[:sleep_time].to_f
|
473
|
-
store_rule(
|
460
|
+
step_definition.store_rule(rule) if sleep_value > rule.conditions[:min]
|
474
461
|
end
|
475
|
-
end
|
462
|
+
end}
|
476
463
|
},
|
477
464
|
:todo => {
|
478
465
|
:enabled => true,
|
479
466
|
:phrase => "Todo found. Resolve it.",
|
480
467
|
:score => INFO,
|
481
468
|
:targets => ["StepDefinition"],
|
482
|
-
:reason =>
|
483
|
-
false"
|
469
|
+
:reason => lambda { |step_definition, rule| step_definition.store_rule_many_times(rule, step_definition.todo.size)}
|
484
470
|
},
|
485
471
|
:hook_not_in_hooks_file => {
|
486
472
|
:enabled => true,
|
@@ -488,7 +474,7 @@ module CukeSniffer
|
|
488
474
|
:score => INFO,
|
489
475
|
:file => "hooks.rb",
|
490
476
|
:targets => ["Hook"],
|
491
|
-
:reason =>
|
477
|
+
:reason => lambda { |hook, rule| hook.location.include?(rule.conditions[:file]) != true}
|
492
478
|
},
|
493
479
|
}
|
494
480
|
|