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,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
3
|
+
|
2
4
|
require 'cuke_sniffer'
|
3
5
|
|
4
6
|
help_cmd_txt = "Welcome to CukeSniffer!
|
@@ -19,7 +21,8 @@ if ARGV.include? "-h" or ARGV.include? "--help"
|
|
19
21
|
end
|
20
22
|
|
21
23
|
cuke_sniffer = nil
|
22
|
-
if (ARGV[0] != nil and File.directory?(ARGV[0])) and (ARGV[1] != nil and File.directory?
|
24
|
+
if (ARGV[0] != nil and File.directory?(ARGV[0])) and (ARGV[1] != nil and File.directory?
|
25
|
+
(ARGV[1]))
|
23
26
|
cuke_sniffer = CukeSniffer::CLI.new(ARGV[0], ARGV[1])
|
24
27
|
else
|
25
28
|
cuke_sniffer = CukeSniffer::CLI.new
|
data/lib/cuke_sniffer.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
require 'nokogiri'
|
2
|
-
require 'roxml'
|
3
|
-
|
4
|
-
require 'cuke_sniffer/constants'
|
5
|
-
require 'cuke_sniffer/rule_config'
|
6
|
-
require 'cuke_sniffer/rules_evaluator'
|
7
|
-
require 'cuke_sniffer/feature_rules_evaluator'
|
8
|
-
require 'cuke_sniffer/feature'
|
9
|
-
require 'cuke_sniffer/scenario'
|
10
|
-
require 'cuke_sniffer/step_definition'
|
11
|
-
require 'cuke_sniffer/
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'roxml'
|
3
|
+
|
4
|
+
require 'cuke_sniffer/constants'
|
5
|
+
require 'cuke_sniffer/rule_config'
|
6
|
+
require 'cuke_sniffer/rules_evaluator'
|
7
|
+
require 'cuke_sniffer/feature_rules_evaluator'
|
8
|
+
require 'cuke_sniffer/feature'
|
9
|
+
require 'cuke_sniffer/scenario'
|
10
|
+
require 'cuke_sniffer/step_definition'
|
11
|
+
require 'cuke_sniffer/hook'
|
12
|
+
require 'cuke_sniffer/cli'
|
13
|
+
|
14
|
+
module CukeSniffer
|
15
|
+
|
16
|
+
end
|
data/lib/cuke_sniffer/cli.rb
CHANGED
@@ -2,6 +2,11 @@ require 'erb'
|
|
2
2
|
require 'roxml'
|
3
3
|
|
4
4
|
module CukeSniffer
|
5
|
+
|
6
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
7
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
8
|
+
# License:: Distributes under the MIT License
|
9
|
+
# Mixins: CukeSniffer::Constants, ROXML
|
5
10
|
class CLI
|
6
11
|
include CukeSniffer::Constants
|
7
12
|
include ROXML
|
@@ -14,26 +19,80 @@ module CukeSniffer
|
|
14
19
|
xml_accessor :good
|
15
20
|
xml_accessor :bad
|
16
21
|
xml_accessor :threshold
|
17
|
-
end
|
22
|
+
end # :nodoc:
|
18
23
|
|
19
24
|
xml_name "cuke_sniffer"
|
20
25
|
xml_accessor :features_summary, :as => SummaryNode
|
21
26
|
xml_accessor :scenarios_summary, :as => SummaryNode
|
22
27
|
xml_accessor :step_definitions_summary, :as => SummaryNode
|
23
|
-
xml_accessor :
|
28
|
+
xml_accessor :hooks_summary, :as => SummaryNode
|
29
|
+
xml_accessor :improvement_list, :as => {:key => "rule", :value => "total"}, :in => "improvement_list", :from => "improvement"
|
24
30
|
xml_accessor :features, :as => [CukeSniffer::Feature], :in => "features"
|
25
31
|
xml_accessor :step_definitions, :as => [CukeSniffer::StepDefinition], :in => "step_definitions"
|
32
|
+
xml_accessor :hooks, :as => [CukeSniffer::Hook], :in => "hooks"
|
33
|
+
|
34
|
+
|
35
|
+
# Feature array: All Features gathered from the specified folder
|
36
|
+
attr_accessor :features
|
37
|
+
|
38
|
+
# StepDefinition Array: All StepDefinitions objects gathered from the specified folder
|
39
|
+
attr_accessor :step_definitions
|
40
|
+
|
41
|
+
# Hash: Summary objects and improvement lists
|
42
|
+
# * Key: symbol, :total_score, :features, :step_definitions, :improvement_list
|
43
|
+
# * Value: hash or array
|
44
|
+
attr_accessor :summary
|
45
|
+
|
46
|
+
# string: Location of the feature file or root folder that was searched in
|
47
|
+
attr_accessor :features_location
|
26
48
|
|
27
|
-
|
49
|
+
# string: Location of the step definition file or root folder that was searched in
|
50
|
+
attr_accessor :step_definitions_location
|
28
51
|
|
29
|
-
|
52
|
+
# string: Location of the hook file or root folder that was searched in
|
53
|
+
attr_accessor :hooks_location
|
54
|
+
|
55
|
+
# Scenario array: All Scenarios found in the features from the specified folder
|
56
|
+
attr_accessor :scenarios
|
57
|
+
|
58
|
+
# Hook array: All Hooks found in the current directory
|
59
|
+
attr_accessor :hooks
|
60
|
+
|
61
|
+
|
62
|
+
# Does analysis against the passed features and step definition locations
|
63
|
+
#
|
64
|
+
# Can be called in several ways.
|
65
|
+
#
|
66
|
+
#
|
67
|
+
# No argument(assumes current directory is the project)
|
68
|
+
# cuke_sniffer = CukeSniffer::CLI.new
|
69
|
+
#
|
70
|
+
# Against single files
|
71
|
+
# cuke_sniffer = CukeSniffer::CLI.new("my_feature.feature", nil)
|
72
|
+
# Or
|
73
|
+
# cuke_sniffer = CukeSniffer::CLI.new(nil, "my_steps.rb")
|
74
|
+
#
|
75
|
+
#
|
76
|
+
# Against folders
|
77
|
+
# cuke_sniffer = CukeSniffer::CLI.new("my_features_directory\", "my_steps_directory\")
|
78
|
+
#
|
79
|
+
# You can mix and match all of the above examples
|
80
|
+
#
|
81
|
+
# Displays the sequence and a . indicator for each new loop in that process.
|
82
|
+
# Handles creation of all Feature and StepDefinition objects
|
83
|
+
# Then catalogs all step definition calls to be used for rules and identification
|
84
|
+
# of dead steps.
|
85
|
+
def initialize(features_location = Dir.getwd, step_definitions_location = Dir.getwd, hooks_location = Dir.getwd)
|
30
86
|
@features_location = features_location
|
31
87
|
@step_definitions_location = step_definitions_location
|
88
|
+
@hooks_location = hooks_location
|
32
89
|
@features = []
|
33
90
|
@scenarios = []
|
34
91
|
@step_definitions = []
|
92
|
+
@hooks = []
|
35
93
|
|
36
94
|
puts "\nFeatures:"
|
95
|
+
#extract this to a method that accepts a block and yields for the build pattern
|
37
96
|
unless features_location.nil?
|
38
97
|
if File.file?(features_location)
|
39
98
|
@features = [CukeSniffer::Feature.new(features_location)]
|
@@ -58,12 +117,26 @@ module CukeSniffer
|
|
58
117
|
}
|
59
118
|
end
|
60
119
|
end
|
61
|
-
|
62
120
|
@step_definitions.flatten!
|
121
|
+
|
122
|
+
puts("\nHooks:")
|
123
|
+
unless hooks_location.nil?
|
124
|
+
if File.file?(hooks_location)
|
125
|
+
@hooks = [build_hooks(hooks_location)]
|
126
|
+
else
|
127
|
+
build_file_list_from_folder(hooks_location, ".rb").each { |location|
|
128
|
+
@hooks << build_hooks(location)
|
129
|
+
print '.'
|
130
|
+
}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
@hooks.flatten!
|
134
|
+
|
63
135
|
@summary = {
|
64
136
|
:total_score => 0,
|
65
137
|
:features => {},
|
66
138
|
:step_definitions => {},
|
139
|
+
:hooks => {},
|
67
140
|
:improvement_list => {}
|
68
141
|
}
|
69
142
|
puts "\nCataloging Step Calls: "
|
@@ -74,6 +147,165 @@ module CukeSniffer
|
|
74
147
|
@features_summary = load_summary_data(@summary[:features])
|
75
148
|
@scenarios_summary = load_summary_data(@summary[:scenarios])
|
76
149
|
@step_definitions_summary = load_summary_data(@summary[:step_definitions])
|
150
|
+
@hooks_summary = load_summary_data(@summary[:hooks])
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns the status of the overall project based on a comparison of the score to the threshold score
|
154
|
+
def good?
|
155
|
+
@summary[:total_score] <= Constants::THRESHOLDS["Project"]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Calculates the score to threshold percentage of an object
|
159
|
+
# Return: Float
|
160
|
+
def problem_percentage
|
161
|
+
@summary[:total_score].to_f / Constants::THRESHOLDS["Project"].to_f
|
162
|
+
end
|
163
|
+
|
164
|
+
# Prints out a summary of the results and the list of improvements to be made
|
165
|
+
def output_results
|
166
|
+
feature_results = @summary[:features]
|
167
|
+
step_definition_results = @summary[:step_definitions]
|
168
|
+
hooks_results = @summary[:hooks]
|
169
|
+
output = "Suite Summary
|
170
|
+
Total Score: #{@summary[:total_score]}
|
171
|
+
Features (#@features_location)
|
172
|
+
Min: #{feature_results[:min]} (#{feature_results[:min_file]})
|
173
|
+
Max: #{feature_results[:max]} (#{feature_results[:max_file]})
|
174
|
+
Average: #{feature_results[:average]}
|
175
|
+
Step Definitions (#@step_definitions_location)
|
176
|
+
Min: #{step_definition_results[:min]} (#{step_definition_results[:min_file]})
|
177
|
+
Max: #{step_definition_results[:max]} (#{step_definition_results[:max_file]})
|
178
|
+
Average: #{step_definition_results[:average]}
|
179
|
+
Hooks (#@hooks_location)
|
180
|
+
Min: #{hooks_results[:min]} (#{hooks_results[:min_file]})
|
181
|
+
Max: #{hooks_results[:max]} (#{hooks_results[:max_file]})
|
182
|
+
Average: #{hooks_results[:average]}
|
183
|
+
Improvements to make:"
|
184
|
+
create_improvement_list.each { |item| output << "\n #{item}" }
|
185
|
+
output
|
186
|
+
end
|
187
|
+
|
188
|
+
# Creates a html file with the collected project details
|
189
|
+
# file_name defaults to "cuke_sniffer_results.html" unless specified
|
190
|
+
# Second parameter used for passing into the markup.
|
191
|
+
# cuke_sniffer.output_html
|
192
|
+
# Or
|
193
|
+
# cuke_sniffer.output_html("results01-01-0001.html")
|
194
|
+
def output_html(file_name = "cuke_sniffer_results.html", cuke_sniffer = self)
|
195
|
+
@features = @features.sort_by { |feature| feature.total_score }.reverse
|
196
|
+
@step_definitions = @step_definitions.sort_by { |step_definition| step_definition.score }.reverse
|
197
|
+
@hooks = @hooks.sort_by { |hook| hook.score }.reverse
|
198
|
+
|
199
|
+
markup_erb = ERB.new extract_markup
|
200
|
+
output = markup_erb.result(binding)
|
201
|
+
File.open(file_name, 'w') do |f|
|
202
|
+
f.write(output)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Creates a xml file with the collected project details
|
207
|
+
# file_name defaults to "cuke_sniffer.xml" unless specified
|
208
|
+
# cuke_sniffer.output_xml
|
209
|
+
# Or
|
210
|
+
# cuke_sniffer.output_xml("cuke_sniffer01-01-0001.xml")
|
211
|
+
def output_xml(file_name = "cuke_sniffer.xml")
|
212
|
+
doc = Nokogiri::XML::Document.new
|
213
|
+
doc.root = self.to_xml
|
214
|
+
open(file_name, "w") do |file|
|
215
|
+
file << doc.serialize
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Gathers all StepDefinitions that have no calls
|
220
|
+
# Returns a hash that has two different types of records
|
221
|
+
# 1: String of the file with a dead step with an array of the line and regex of each dead step
|
222
|
+
# 2: Symbol of :total with an integer that is the total number of dead steps
|
223
|
+
def get_dead_steps
|
224
|
+
dead_steps_hash = {}
|
225
|
+
@step_definitions.each do |step_definition|
|
226
|
+
location_match = step_definition.location.match(/(?<file>.*).rb:(?<line>\d+)/)
|
227
|
+
file_name = location_match[:file]
|
228
|
+
regex = step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex]
|
229
|
+
dead_steps_hash[file_name] ||= []
|
230
|
+
dead_steps_hash[file_name] << "#{location_match[:line]}: /#{regex}/" if step_definition.calls.empty?
|
231
|
+
end
|
232
|
+
total = 0
|
233
|
+
dead_steps_hash.each_key do |key|
|
234
|
+
unless dead_steps_hash[key] == []
|
235
|
+
total += dead_steps_hash[key].size
|
236
|
+
dead_steps_hash[key].sort_by! { |row| row[/^\d+/].to_i }
|
237
|
+
else
|
238
|
+
dead_steps_hash.delete(key)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
dead_steps_hash[:total] = total
|
242
|
+
dead_steps_hash
|
243
|
+
end
|
244
|
+
|
245
|
+
# Determines all normal and nested step calls and assigns them to the corresponding step definition.
|
246
|
+
# Does direct and fuzzy matching
|
247
|
+
def catalog_step_calls
|
248
|
+
steps = get_all_steps
|
249
|
+
@step_definitions.each do |step_definition|
|
250
|
+
print '.'
|
251
|
+
calls = steps.find_all { |location, step| step.gsub(STEP_STYLES, "") =~ step_definition.regex }
|
252
|
+
calls.each { |call| step_definition.add_call(call[0], call[1].gsub(STEP_STYLES, "")) }
|
253
|
+
end
|
254
|
+
|
255
|
+
converted_steps = convert_steps_with_expressions(get_steps_with_expressions(steps))
|
256
|
+
catalog_possible_dead_steps(converted_steps)
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
def extract_variables_from_example(example)
|
262
|
+
example = example[example.index('|')..example.length]
|
263
|
+
example.split(/\s*\|\s*/) - [""]
|
264
|
+
end
|
265
|
+
|
266
|
+
def assess_score
|
267
|
+
@summary[:features] = assess_array(@features, "Feature")
|
268
|
+
@summary[:scenarios] = assess_array(@scenarios, "Scenario")
|
269
|
+
@summary[:step_definitions] = assess_array(@step_definitions, "StepDefinition")
|
270
|
+
@summary[:hooks] = assess_array(@hooks, "Hook")
|
271
|
+
sort_improvement_list
|
272
|
+
end
|
273
|
+
|
274
|
+
def get_all_steps
|
275
|
+
feature_steps = extract_steps_from_features
|
276
|
+
step_definition_steps = extract_steps_from_step_definitions
|
277
|
+
feature_steps.merge step_definition_steps
|
278
|
+
end
|
279
|
+
|
280
|
+
def get_steps_with_expressions(steps)
|
281
|
+
steps_with_expressions = {}
|
282
|
+
steps.each do |step_location, step_value|
|
283
|
+
if step_value =~ /\#{.*}/
|
284
|
+
steps_with_expressions[step_location] = step_value
|
285
|
+
end
|
286
|
+
end
|
287
|
+
steps_with_expressions
|
288
|
+
end
|
289
|
+
|
290
|
+
def catalog_possible_dead_steps(steps_with_expressions)
|
291
|
+
@step_definitions.each do |step_definition|
|
292
|
+
next unless step_definition.calls.empty?
|
293
|
+
regex_as_string = step_definition.regex.to_s.gsub(/\(\?-mix:\^?/, "").gsub(/\$\)$/, "")
|
294
|
+
steps_with_expressions.each do |step_location, step_value|
|
295
|
+
if regex_as_string =~ step_value
|
296
|
+
step_definition.add_call(step_location, step_value)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def convert_steps_with_expressions(steps_with_expressions)
|
303
|
+
step_regexs = {}
|
304
|
+
steps_with_expressions.each do |step_location, step_value|
|
305
|
+
modified_step = step_value.gsub(/\#{[^}]*}/, '.*')
|
306
|
+
step_regexs[step_location] = Regexp.new('^' + modified_step + '$')
|
307
|
+
end
|
308
|
+
step_regexs
|
77
309
|
end
|
78
310
|
|
79
311
|
def load_summary_data(summary_hash)
|
@@ -87,14 +319,6 @@ module CukeSniffer
|
|
87
319
|
summary_node
|
88
320
|
end
|
89
321
|
|
90
|
-
def good?
|
91
|
-
@summary[:total_score] <= Constants::THRESHOLDS["Project"]
|
92
|
-
end
|
93
|
-
|
94
|
-
def problem_percentage
|
95
|
-
@summary[:total_score].to_f / Constants::THRESHOLDS["Project"].to_f
|
96
|
-
end
|
97
|
-
|
98
322
|
def build_file_list_from_folder(folder_name, extension)
|
99
323
|
list = []
|
100
324
|
Dir.entries(folder_name).each_entry do |file_name|
|
@@ -129,7 +353,7 @@ module CukeSniffer
|
|
129
353
|
step_code << step_file_lines[counter].strip
|
130
354
|
counter+=1
|
131
355
|
end
|
132
|
-
step_definitions << CukeSniffer::StepDefinition.new("#{file_name}:#{counter+1}", step_code) unless step_code.empty? or !found_first_step
|
356
|
+
step_definitions << CukeSniffer::StepDefinition.new("#{file_name}:#{counter+1 -step_code.count}", step_code) unless step_code.empty? or !found_first_step
|
133
357
|
step_definitions
|
134
358
|
end
|
135
359
|
|
@@ -139,22 +363,24 @@ module CukeSniffer
|
|
139
363
|
good = 0
|
140
364
|
bad = 0
|
141
365
|
total_score = 0
|
142
|
-
array.
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
good
|
154
|
-
|
155
|
-
|
366
|
+
unless array.empty?
|
367
|
+
array.each do |node|
|
368
|
+
score = node.score
|
369
|
+
@summary[:total_score] += score
|
370
|
+
total_score += score
|
371
|
+
node.rules_hash.each_key do |key|
|
372
|
+
@summary[:improvement_list][key] ||= 0
|
373
|
+
@summary[:improvement_list][key] += node.rules_hash[key]
|
374
|
+
end
|
375
|
+
min, min_file = score, node.location if (min.nil? or score < min)
|
376
|
+
max, max_file = score, node.location if (max.nil? or score > max)
|
377
|
+
if node.good?
|
378
|
+
good += 1
|
379
|
+
else
|
380
|
+
bad += 1
|
381
|
+
end
|
382
|
+
total += score
|
156
383
|
end
|
157
|
-
total += score
|
158
384
|
end
|
159
385
|
{
|
160
386
|
:total => array.count,
|
@@ -170,13 +396,6 @@ module CukeSniffer
|
|
170
396
|
}
|
171
397
|
end
|
172
398
|
|
173
|
-
def assess_score
|
174
|
-
@summary[:features] = assess_array(@features, "Feature")
|
175
|
-
@summary[:scenarios] = assess_array(@scenarios, "Scenario")
|
176
|
-
@summary[:step_definitions] = assess_array(@step_definitions, "StepDefinition") unless @step_definitions.empty?
|
177
|
-
sort_improvement_list
|
178
|
-
end
|
179
|
-
|
180
399
|
def get_all_scenarios(features)
|
181
400
|
scenarios = []
|
182
401
|
features.each do |feature|
|
@@ -194,31 +413,28 @@ module CukeSniffer
|
|
194
413
|
}
|
195
414
|
end
|
196
415
|
|
197
|
-
def output_results
|
198
|
-
feature_results = @summary[:features]
|
199
|
-
step_definition_results = @summary[:step_definitions]
|
200
|
-
output = "Suite Summary
|
201
|
-
Total Score: #{@summary[:total_score]}
|
202
|
-
Features (#@features_location)
|
203
|
-
Min: #{feature_results[:min]} (#{feature_results[:min_file]})
|
204
|
-
Max: #{feature_results[:max]} (#{feature_results[:max_file]})
|
205
|
-
Average: #{feature_results[:average]}
|
206
|
-
Step Definitions (#@step_definitions_location)
|
207
|
-
Min: #{step_definition_results[:min]} (#{step_definition_results[:min_file]})
|
208
|
-
Max: #{step_definition_results[:max]} (#{step_definition_results[:max_file]})
|
209
|
-
Average: #{step_definition_results[:average]}
|
210
|
-
Improvements to make:"
|
211
|
-
create_improvement_list.each { |item| output << "\n #{item}" }
|
212
|
-
output
|
213
|
-
end
|
214
|
-
|
215
416
|
def create_improvement_list
|
216
417
|
output = []
|
217
418
|
@summary[:improvement_list].each_key { |improvement| output << "(#{summary[:improvement_list][improvement]})#{improvement}" }
|
218
419
|
output
|
219
420
|
end
|
220
421
|
|
221
|
-
def
|
422
|
+
def extract_steps_from_features
|
423
|
+
steps = {}
|
424
|
+
@features.each do |feature|
|
425
|
+
steps.merge! extract_scenario_steps(feature.background) unless feature.background.nil?
|
426
|
+
feature.scenarios.each do |scenario|
|
427
|
+
if scenario.type == "Scenario Outline"
|
428
|
+
steps.merge! extract_scenario_outline_steps(scenario)
|
429
|
+
else
|
430
|
+
steps.merge! extract_scenario_steps(scenario)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
steps
|
435
|
+
end
|
436
|
+
|
437
|
+
def extract_scenario_steps(scenario)
|
222
438
|
steps_hash = {}
|
223
439
|
counter = 1
|
224
440
|
scenario.steps.each do |step|
|
@@ -229,57 +445,46 @@ module CukeSniffer
|
|
229
445
|
steps_hash
|
230
446
|
end
|
231
447
|
|
232
|
-
def
|
448
|
+
def extract_scenario_outline_steps(scenario)
|
233
449
|
steps = {}
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
450
|
+
examples = scenario.examples_table
|
451
|
+
return {} if examples.empty?
|
452
|
+
variable_list = extract_variables_from_example(examples.first)
|
453
|
+
(1...examples.size).each do |example_counter|
|
454
|
+
#TODO Abstraction needed for this regex matcher (constants?)
|
455
|
+
next if examples[example_counter] =~ /^\#.*$/
|
456
|
+
row_variables = extract_variables_from_example(examples[example_counter])
|
457
|
+
step_counter = 1
|
458
|
+
scenario.steps.each do |step|
|
459
|
+
step_line = scenario.start_line + step_counter
|
460
|
+
location = "#{scenario.location.gsub(/\d+$/, step_line.to_s)}(Example #{example_counter})"
|
461
|
+
steps[location] = build_updated_step_from_example(step, variable_list, row_variables)
|
462
|
+
step_counter += 1
|
247
463
|
end
|
248
464
|
end
|
249
465
|
steps
|
250
466
|
end
|
251
467
|
|
252
|
-
def
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
468
|
+
def build_updated_step_from_example(step, variable_list, row_variables)
|
469
|
+
new_step = step.dup
|
470
|
+
variable_list.each do |variable|
|
471
|
+
if step.include? variable
|
472
|
+
table_variable_to_insert = row_variables[variable_list.index(variable)]
|
473
|
+
table_variable_to_insert ||= ""
|
474
|
+
new_step.gsub!("<#{variable}>", table_variable_to_insert)
|
475
|
+
end
|
260
476
|
end
|
477
|
+
new_step
|
261
478
|
end
|
262
479
|
|
263
|
-
def
|
264
|
-
|
265
|
-
@step_definitions.each do |
|
266
|
-
|
267
|
-
|
268
|
-
regex = step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex]
|
269
|
-
dead_steps_hash[file_name] ||= []
|
270
|
-
dead_steps_hash[file_name] << "#{location_match[:line]}: /#{regex}/" if step_definition.calls.empty?
|
271
|
-
end
|
272
|
-
total = 0
|
273
|
-
dead_steps_hash.each_key do |key|
|
274
|
-
unless dead_steps_hash[key] == []
|
275
|
-
total += dead_steps_hash[key].size
|
276
|
-
dead_steps_hash[key].sort_by! {|row| row[/^\d+/].to_i}
|
277
|
-
else
|
278
|
-
dead_steps_hash.delete(key)
|
480
|
+
def extract_steps_from_step_definitions
|
481
|
+
steps = {}
|
482
|
+
@step_definitions.each do |definition|
|
483
|
+
definition.nested_steps.each_key do |key|
|
484
|
+
steps[key] = definition.nested_steps[key]
|
279
485
|
end
|
280
486
|
end
|
281
|
-
|
282
|
-
dead_steps_hash
|
487
|
+
steps
|
283
488
|
end
|
284
489
|
|
285
490
|
def extract_markup
|
@@ -291,24 +496,28 @@ module CukeSniffer
|
|
291
496
|
markup
|
292
497
|
end
|
293
498
|
|
294
|
-
def
|
295
|
-
|
296
|
-
|
499
|
+
def build_hooks(file_name)
|
500
|
+
hooks_file_lines = []
|
501
|
+
hooks_file = File.open(file_name)
|
502
|
+
hooks_file.each_line { |line| hooks_file_lines << line }
|
503
|
+
hooks_file.close
|
297
504
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
505
|
+
counter = 0
|
506
|
+
hooks_code = []
|
507
|
+
hooks = []
|
508
|
+
found_first_hook = false
|
509
|
+
until counter >= hooks_file_lines.length
|
510
|
+
if hooks_file_lines[counter] =~ HOOK_REGEX and !hooks_code.empty? and found_first_hook
|
511
|
+
hooks << CukeSniffer::Hook.new("#{file_name}:#{counter+1 - hooks_code.count}", hooks_code)
|
512
|
+
hooks_code = []
|
513
|
+
end
|
514
|
+
found_first_hook = true if hooks_file_lines[counter] =~ HOOK_REGEX
|
515
|
+
hooks_code << hooks_file_lines[counter].strip
|
516
|
+
counter+=1
|
302
517
|
end
|
518
|
+
hooks << CukeSniffer::Hook.new("#{file_name}:#{counter+1 -hooks_code.count}", hooks_code) unless hooks_code.empty? or !found_first_hook
|
519
|
+
hooks
|
303
520
|
end
|
304
521
|
|
305
|
-
def output_xml(file_name = "cuke_sniffer.xml")
|
306
|
-
doc = Nokogiri::XML::Document.new
|
307
|
-
doc.root = self.to_xml
|
308
|
-
open(file_name, "w") do |file|
|
309
|
-
file << doc.serialize
|
310
|
-
end
|
311
|
-
|
312
|
-
end
|
313
522
|
end
|
314
523
|
end
|