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,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
|