cuke_sniffer 0.0.3 → 0.0.5
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/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
|