cuke_sniffer 0.0.7 → 0.0.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/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
|
|