cuke_sniffer 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/{cuke_sniffer.rb → cuke_sniffer} +4 -1
- data/lib/cuke_sniffer.rb +16 -15
- data/lib/cuke_sniffer/cli.rb +319 -110
- data/lib/cuke_sniffer/constants.rb +34 -22
- data/lib/cuke_sniffer/feature.rb +77 -22
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +115 -69
- data/lib/cuke_sniffer/hook.rb +160 -0
- data/lib/cuke_sniffer/report/markup.rhtml +266 -308
- data/lib/cuke_sniffer/rule_config.rb +192 -94
- data/lib/cuke_sniffer/rules_evaluator.rb +70 -53
- data/lib/cuke_sniffer/scenario.rb +238 -178
- data/lib/cuke_sniffer/step_definition.rb +239 -202
- metadata +6 -5
@@ -1,178 +1,238 @@
|
|
1
|
-
module CukeSniffer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
132
|
-
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
@steps.each do |step|
|
142
|
-
|
143
|
-
rule
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
end
|
1
|
+
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# This class is a representation of the cucumber objects
|
7
|
+
# Background, Scenario, Scenario Outline
|
8
|
+
#
|
9
|
+
# Extends CukeSniffer::FeatureRulesEvaluator
|
10
|
+
class Scenario < FeatureRulesEvaluator
|
11
|
+
|
12
|
+
xml_accessor :start_line
|
13
|
+
xml_accessor :steps, :as => [], :in => "steps"
|
14
|
+
xml_accessor :examples_table, :as => [], :in => "examples"
|
15
|
+
|
16
|
+
# int: Line on which the scenario begins
|
17
|
+
attr_accessor :start_line
|
18
|
+
|
19
|
+
# string: The type of scenario
|
20
|
+
# Background, Scenario, Scenario Outline
|
21
|
+
attr_accessor :type
|
22
|
+
|
23
|
+
# string array: List of each step call in a scenario
|
24
|
+
attr_accessor :steps
|
25
|
+
|
26
|
+
# hash: Keeps each location and content of an inline table
|
27
|
+
# * Key: Step string the inline table is attached to
|
28
|
+
# * Value: Array of all of the lines in the table
|
29
|
+
attr_accessor :inline_tables
|
30
|
+
|
31
|
+
# string array: List of each example row in a scenario outline
|
32
|
+
attr_accessor :examples_table
|
33
|
+
|
34
|
+
# Location must be in the format of "file_path\file_name.rb:line_number"
|
35
|
+
# Scenario must be a string array containing everything from the first tag to the last example table
|
36
|
+
# where applicable.
|
37
|
+
def initialize(location, scenario)
|
38
|
+
super(location)
|
39
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
40
|
+
@steps = []
|
41
|
+
@inline_tables = {}
|
42
|
+
@examples_table = []
|
43
|
+
split_scenario(scenario)
|
44
|
+
evaluate_score
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(comparison_object) # :nodoc:
|
48
|
+
super(comparison_object) &&
|
49
|
+
comparison_object.steps == steps &&
|
50
|
+
comparison_object.examples_table == examples_table
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def split_scenario(scenario)
|
56
|
+
index = 0
|
57
|
+
until index >= scenario.length or scenario[index] =~ SCENARIO_TITLE_STYLES
|
58
|
+
update_tag_list(scenario[index])
|
59
|
+
index += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
until index >= scenario.length or scenario[index].match STEP_REGEX or scenario[index].include?("Examples:")
|
63
|
+
match = scenario[index].match(SCENARIO_TITLE_STYLES)
|
64
|
+
@type = match[:type] unless match.nil?
|
65
|
+
create_name(scenario[index], SCENARIO_TITLE_STYLES)
|
66
|
+
index += 1
|
67
|
+
end
|
68
|
+
|
69
|
+
until index >= scenario.length or scenario[index].include?("Examples:")
|
70
|
+
if scenario[index] =~ /^\|.*\|/
|
71
|
+
step = scenario[index - 1]
|
72
|
+
@inline_tables[step] = []
|
73
|
+
until index >= scenario.length or scenario[index] =~ /(#{STEP_REGEX}|^\s*Examples:)/
|
74
|
+
@inline_tables[step] << scenario[index]
|
75
|
+
index += 1
|
76
|
+
end
|
77
|
+
else
|
78
|
+
@steps << scenario[index] if scenario[index] =~ STEP_REGEX
|
79
|
+
index += 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if index < scenario.length and scenario[index].include?("Examples:")
|
84
|
+
index += 1
|
85
|
+
until index >= scenario.length
|
86
|
+
index += 2 if scenario[index].include?("Examples:")
|
87
|
+
@examples_table << scenario[index] if scenario[index] =~ /#{COMMENT_REGEX}\|.*\|/
|
88
|
+
index += 1
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_step_order
|
94
|
+
order = []
|
95
|
+
@steps.each do |line|
|
96
|
+
next if is_comment?(line)
|
97
|
+
match = line.match(STEP_REGEX)
|
98
|
+
order << match[:style] unless match.nil?
|
99
|
+
end
|
100
|
+
order
|
101
|
+
end
|
102
|
+
|
103
|
+
def evaluate_score
|
104
|
+
if type == "Background"
|
105
|
+
rule_numbers_in_name(type)
|
106
|
+
rule_long_name(type)
|
107
|
+
rule_tagged_background(type)
|
108
|
+
else
|
109
|
+
super
|
110
|
+
rule_step_order
|
111
|
+
end
|
112
|
+
|
113
|
+
rule_empty_scenario
|
114
|
+
rule_too_many_steps
|
115
|
+
rule_invalid_first_step
|
116
|
+
rule_asterisk_step
|
117
|
+
rule_commented_step
|
118
|
+
rule_implementation_words
|
119
|
+
rule_date_used_in_step
|
120
|
+
rule_one_word_step
|
121
|
+
rule_multiple_given_when_then
|
122
|
+
evaluate_outline_scores if type == "Scenario Outline"
|
123
|
+
end
|
124
|
+
|
125
|
+
def evaluate_outline_scores
|
126
|
+
rule_no_examples_table
|
127
|
+
rule_no_examples
|
128
|
+
rule_one_example
|
129
|
+
rule_too_many_examples
|
130
|
+
rule_commented_example
|
131
|
+
end
|
132
|
+
|
133
|
+
def rule_multiple_given_when_then
|
134
|
+
step_order = get_step_order
|
135
|
+
rule = RULES[:multiple_given_when_then]
|
136
|
+
phrase = rule[:phrase].gsub(/{.*}/, type)
|
137
|
+
["Given", "When", "Then"].each { |step| store_rule(rule, phrase) if step_order.count(step) > 1 }
|
138
|
+
end
|
139
|
+
|
140
|
+
def rule_one_word_step
|
141
|
+
@steps.each do |step|
|
142
|
+
rule = RULES[:one_word_step]
|
143
|
+
store_rule(rule) if step.split.count == 2
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def rule_step_order
|
148
|
+
step_order = get_step_order.uniq
|
149
|
+
["But", "*", "And"].each { |type| step_order.delete(type) }
|
150
|
+
rule = RULES[:out_of_order_steps]
|
151
|
+
store_rule(rule) unless step_order == %w(Given When Then) or step_order == %w(When Then)
|
152
|
+
end
|
153
|
+
|
154
|
+
def rule_asterisk_step
|
155
|
+
get_step_order.count('*').times do
|
156
|
+
rule = RULES[:asterisk_step]
|
157
|
+
store_rule(rule)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def rule_commented_step
|
162
|
+
@steps.each do |step|
|
163
|
+
rule = RULES[:commented_step]
|
164
|
+
store_rule(rule) if is_comment?(step)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def rule_date_used_in_step
|
169
|
+
@steps.each do |step|
|
170
|
+
rule = RULES[:date_used]
|
171
|
+
store_rule(rule) if step =~ DATE_REGEX
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def rule_no_examples_table
|
176
|
+
rule = RULES[:no_examples_table]
|
177
|
+
store_rule(rule) if @examples_table.empty?
|
178
|
+
end
|
179
|
+
|
180
|
+
def rule_no_examples
|
181
|
+
rule = RULES[:no_examples]
|
182
|
+
store_rule(rule) if @examples_table.size == 1
|
183
|
+
end
|
184
|
+
|
185
|
+
def rule_one_example
|
186
|
+
rule = RULES[:one_example]
|
187
|
+
store_rule(rule) if @examples_table.size == 2 and !is_comment?(@examples_table[1])
|
188
|
+
end
|
189
|
+
|
190
|
+
def rule_too_many_examples
|
191
|
+
rule = RULES[:too_many_examples]
|
192
|
+
store_rule(rule) if (@examples_table.size - 1) >= 8
|
193
|
+
end
|
194
|
+
|
195
|
+
def rule_commented_example
|
196
|
+
@examples_table.each do |example|
|
197
|
+
rule = RULES[:commented_example]
|
198
|
+
store_rule(rule) if is_comment?(example)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def rule_implementation_words
|
203
|
+
rule = RULES[:implementation_word]
|
204
|
+
@steps.each do |step|
|
205
|
+
next if is_comment?(step)
|
206
|
+
rule[:words].each do |word|
|
207
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, word)
|
208
|
+
store_rule(rule, rule_phrase) if step.include?(word)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def rule_tagged_background(type)
|
214
|
+
rule = RULES[:background_with_tag]
|
215
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
216
|
+
store_rule(rule, rule_phrase) if tags.size > 0
|
217
|
+
end
|
218
|
+
|
219
|
+
def rule_invalid_first_step
|
220
|
+
first_step = get_step_order.first
|
221
|
+
rule = RULES[:invalid_first_step]
|
222
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
223
|
+
store_rule(rule, rule_phrase) if %w(And But).include?(first_step)
|
224
|
+
end
|
225
|
+
|
226
|
+
def rule_empty_scenario
|
227
|
+
rule = RULES[:no_steps]
|
228
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
229
|
+
store_rule(rule, rule_phrase) if @steps.empty?
|
230
|
+
end
|
231
|
+
|
232
|
+
def rule_too_many_steps
|
233
|
+
rule = RULES[:too_many_steps]
|
234
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
235
|
+
store_rule(rule, rule_phrase) if @steps.size >= rule[:max]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -1,202 +1,239 @@
|
|
1
|
-
require 'roxml'
|
2
|
-
module CukeSniffer
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
xml_accessor :
|
12
|
-
xml_accessor :
|
13
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
@
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
store_rule(
|
187
|
-
end
|
188
|
-
|
189
|
-
def
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
code.each do |line|
|
197
|
-
store_rule(
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
1
|
+
require 'roxml'
|
2
|
+
module CukeSniffer
|
3
|
+
|
4
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
5
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
6
|
+
# License:: Distributes under the MIT License
|
7
|
+
# Translates and evaluates Cucumber step definitions
|
8
|
+
# Extends CukeSniffer::RulesEvaluator
|
9
|
+
class StepDefinition < RulesEvaluator
|
10
|
+
|
11
|
+
xml_accessor :start_line
|
12
|
+
xml_accessor :regex
|
13
|
+
xml_accessor :parameters, :as => [], :in => "parameters"
|
14
|
+
xml_accessor :nested_steps, :as => {:key => 'location', :value => 'call'}, :in => "nested_steps"
|
15
|
+
xml_accessor :calls, :as => {:key => 'location', :value => 'call'}, :in => "calls"
|
16
|
+
xml_accessor :code, :as => [], :in => "code"
|
17
|
+
|
18
|
+
# int: Line on which a step definition starts
|
19
|
+
attr_accessor :start_line
|
20
|
+
|
21
|
+
# Regex: Regex that cucumber uses to match step calls
|
22
|
+
attr_accessor :regex
|
23
|
+
|
24
|
+
# string array: List of the parameters a step definition has
|
25
|
+
attr_accessor :parameters
|
26
|
+
|
27
|
+
# hash: Contains each nested step call a step definition has
|
28
|
+
# * Key: location:line of the nested step
|
29
|
+
# * Value: The step call that appears on the line
|
30
|
+
attr_accessor :nested_steps
|
31
|
+
|
32
|
+
# hash: Contains each call that is made to a step definition
|
33
|
+
# * Key: Location in which the step definition is called from
|
34
|
+
# * Value: The step string that matched the regex
|
35
|
+
# In the case of a fuzzy match it will be a regex of the
|
36
|
+
# step call that was the inverse match of the regex translated
|
37
|
+
# into a string.
|
38
|
+
attr_accessor :calls
|
39
|
+
|
40
|
+
# string array: List of all of the content between the regex and the end of the step definition.
|
41
|
+
attr_accessor :code
|
42
|
+
|
43
|
+
# location must be in the format of "file_path\file_name.rb:line_number"
|
44
|
+
# raw_code is an array of strings that represents the step definition
|
45
|
+
# must contain the regex line and its pairing end
|
46
|
+
def initialize(location, raw_code)
|
47
|
+
super(location)
|
48
|
+
|
49
|
+
@parameters = []
|
50
|
+
@calls = {}
|
51
|
+
@nested_steps = {}
|
52
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
53
|
+
|
54
|
+
end_match_index = (raw_code.size - 1) - raw_code.reverse.index("end")
|
55
|
+
@code = raw_code[1...end_match_index]
|
56
|
+
|
57
|
+
raw_code.each do |line|
|
58
|
+
if line =~ STEP_DEFINITION_REGEX
|
59
|
+
matches = STEP_DEFINITION_REGEX.match(line)
|
60
|
+
@regex = Regexp.new(matches[:step])
|
61
|
+
@parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
detect_nested_steps
|
66
|
+
evaluate_score
|
67
|
+
end
|
68
|
+
|
69
|
+
# Adds new location => step_string pairs to the calls hash
|
70
|
+
def add_call(location, step_string)
|
71
|
+
@calls[location] = step_string
|
72
|
+
end
|
73
|
+
|
74
|
+
def ==(comparison_object) # :nodoc:
|
75
|
+
super(comparison_object) &&
|
76
|
+
comparison_object.regex == regex &&
|
77
|
+
comparison_object.code == code &&
|
78
|
+
comparison_object.parameters == parameters &&
|
79
|
+
comparison_object.calls == calls &&
|
80
|
+
comparison_object.nested_steps == nested_steps
|
81
|
+
end
|
82
|
+
|
83
|
+
def condensed_call_list
|
84
|
+
condensed_list = {}
|
85
|
+
@calls.each do |call, step_string|
|
86
|
+
condensed_list[step_string] ||= []
|
87
|
+
condensed_list[step_string] << call
|
88
|
+
end
|
89
|
+
condensed_list
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
SIMPLE_NESTED_STEP_REGEX = /steps?\s"#{STEP_STYLES}(?<step_string>.*)"$/ # :nodoc:
|
95
|
+
START_COMPLEX_STEP_REGEX = /^steps?\s%(q|Q)?\{\s*/ # :nodoc:
|
96
|
+
SAME_LINE_COMPLEX_STEP_REGEX = /#{START_COMPLEX_STEP_REGEX}#{STEP_STYLES}(?<step_string>.*)}$/ # :nodoc:
|
97
|
+
END_COMPLEX_STEP_REGEX = /}$/ # :nodoc:
|
98
|
+
START_COMPLEX_WITH_STEP_REGEX = /#{START_COMPLEX_STEP_REGEX}#{STEP_STYLES}(?<step_string>.*)$/ # :nodoc:
|
99
|
+
END_COMPLEX_WITH_STEP_REGEX = /#{STEP_STYLES}(?<step_string>.*)}$/ # :nodoc:
|
100
|
+
|
101
|
+
def detect_nested_steps
|
102
|
+
multi_line_step_flag = false
|
103
|
+
counter = 1
|
104
|
+
@code.each do |line|
|
105
|
+
regex = nil
|
106
|
+
case line
|
107
|
+
when SIMPLE_NESTED_STEP_REGEX
|
108
|
+
regex = SIMPLE_NESTED_STEP_REGEX
|
109
|
+
when SAME_LINE_COMPLEX_STEP_REGEX
|
110
|
+
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
111
|
+
when START_COMPLEX_WITH_STEP_REGEX
|
112
|
+
if line =~ /\}$/
|
113
|
+
if line.include?('#{')
|
114
|
+
reversed_line = line.reverse
|
115
|
+
last_capture = reversed_line[0..reversed_line.index('#')].reverse
|
116
|
+
if last_capture =~ /{.*}$/
|
117
|
+
multi_line_step_flag = true
|
118
|
+
regex = START_COMPLEX_WITH_STEP_REGEX
|
119
|
+
else
|
120
|
+
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
121
|
+
end
|
122
|
+
else
|
123
|
+
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
124
|
+
end
|
125
|
+
else
|
126
|
+
multi_line_step_flag = true
|
127
|
+
regex = START_COMPLEX_WITH_STEP_REGEX
|
128
|
+
end
|
129
|
+
when END_COMPLEX_WITH_STEP_REGEX
|
130
|
+
if line =~ /[#]{.*}$/ && multi_line_step_flag
|
131
|
+
regex = STEP_REGEX
|
132
|
+
else
|
133
|
+
regex = END_COMPLEX_WITH_STEP_REGEX
|
134
|
+
multi_line_step_flag = false
|
135
|
+
end
|
136
|
+
when START_COMPLEX_STEP_REGEX
|
137
|
+
multi_line_step_flag = true
|
138
|
+
when STEP_REGEX
|
139
|
+
regex = STEP_REGEX if multi_line_step_flag
|
140
|
+
when END_COMPLEX_STEP_REGEX
|
141
|
+
multi_line_step_flag = false
|
142
|
+
else
|
143
|
+
end
|
144
|
+
|
145
|
+
if regex and !is_comment?(line)
|
146
|
+
match = regex.match(line)
|
147
|
+
nested_step_line = (@start_line + counter)
|
148
|
+
@nested_steps[location.gsub(/:\d*$/, ":" + nested_step_line.to_s)] = match[:step_string].gsub("\\", "")
|
149
|
+
end
|
150
|
+
counter += 1
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def evaluate_score
|
155
|
+
rule_no_code
|
156
|
+
rule_too_many_parameters
|
157
|
+
rule_nested_steps
|
158
|
+
rule_recursive_nested_step
|
159
|
+
rule_commented_code
|
160
|
+
rule_lazy_debugging
|
161
|
+
rule_pending
|
162
|
+
rule_todo
|
163
|
+
sleep_rules
|
164
|
+
end
|
165
|
+
|
166
|
+
def rule_todo
|
167
|
+
code.each do |line|
|
168
|
+
rule = RULES[:todo]
|
169
|
+
store_rule(rule) if line =~ /\#(TODO|todo)/
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def sleep_rules
|
174
|
+
code.each do |line|
|
175
|
+
match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
|
176
|
+
if match_data
|
177
|
+
sleep_value = match_data[:sleep_time].to_f
|
178
|
+
rule_small_sleep(sleep_value)
|
179
|
+
rule_large_sleep(sleep_value)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def rule_large_sleep(sleep_value)
|
185
|
+
rule = RULES[:large_sleep]
|
186
|
+
store_rule(rule) if sleep_value > rule[:min]
|
187
|
+
end
|
188
|
+
|
189
|
+
def rule_small_sleep(sleep_value)
|
190
|
+
rule = RULES[:small_sleep]
|
191
|
+
store_rule(rule) if sleep_value <= rule[:max]
|
192
|
+
end
|
193
|
+
|
194
|
+
def rule_pending
|
195
|
+
rule = RULES[:pending]
|
196
|
+
code.each do |line|
|
197
|
+
store_rule(rule) if line =~ /^\s*pending\s*$/
|
198
|
+
return
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def rule_lazy_debugging
|
203
|
+
rule = RULES[:lazy_debugging]
|
204
|
+
code.each do |line|
|
205
|
+
next if is_comment?(line)
|
206
|
+
store_rule(rule) if line.strip =~ /^(p|puts)( |\()('|"|%(q|Q)?\{)/
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def rule_no_code
|
211
|
+
rule = RULES[:no_code]
|
212
|
+
store_rule(rule) if code.empty?
|
213
|
+
end
|
214
|
+
|
215
|
+
def rule_too_many_parameters
|
216
|
+
rule = RULES[:too_many_parameters]
|
217
|
+
store_rule(rule) if parameters.size >= rule[:max]
|
218
|
+
end
|
219
|
+
|
220
|
+
def rule_nested_steps
|
221
|
+
rule = RULES[:nested_step]
|
222
|
+
store_rule(rule) unless nested_steps.empty?
|
223
|
+
end
|
224
|
+
|
225
|
+
def rule_recursive_nested_step
|
226
|
+
rule = RULES[:recursive_nested_step]
|
227
|
+
nested_steps.each_value do |nested_step|
|
228
|
+
store_rule(rule) if nested_step =~ regex
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def rule_commented_code
|
233
|
+
rule = RULES[:commented_code]
|
234
|
+
code.each do |line|
|
235
|
+
store_rule(rule) if is_comment?(line)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|