stepdown 0.3.3 → 0.4.0
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/Gemfile +4 -2
- data/Gemfile.lock +14 -10
- data/History.txt +30 -0
- data/README.rdoc +2 -2
- data/Rakefile +13 -0
- data/bin/stepdown +4 -4
- data/lib/stepdown.rb +6 -0
- data/lib/stepdown/analyzer.rb +67 -0
- data/lib/stepdown/feature_parser.rb +30 -0
- data/lib/stepdown/html_reporter.rb +41 -0
- data/lib/stepdown/options.rb +59 -0
- data/lib/stepdown/reporter.rb +106 -0
- data/lib/stepdown/scenario.rb +25 -0
- data/lib/stepdown/step.rb +22 -0
- data/lib/stepdown/step_collection.rb +36 -0
- data/lib/stepdown/step_group.rb +45 -0
- data/lib/stepdown/step_instance.rb +63 -0
- data/lib/stepdown/step_usage.rb +15 -0
- data/lib/stepdown/text_reporter.rb +38 -0
- data/spec/lib/{feature_parser_spec.rb → stepdown/feature_parser_spec.rb} +13 -12
- data/spec/lib/{options_spec.rb → stepdown/options_spec.rb} +24 -6
- data/spec/lib/stepdown/reporter_spec.rb +184 -0
- data/spec/lib/stepdown/scenario_spec.rb +40 -0
- data/spec/lib/stepdown/step_collection_spec.rb +78 -0
- data/spec/lib/stepdown/step_group_spec.rb +43 -0
- data/spec/lib/{step_instance_spec.rb → stepdown/step_instance_spec.rb} +13 -12
- data/spec/spec_helper.rb +4 -0
- data/stepdown.gemspec +7 -4
- data/templates/main.html.haml +3 -3
- data/templates/style.sass +5 -4
- metadata +64 -34
- data/lib/counting_step.rb +0 -14
- data/lib/feature_parser.rb +0 -32
- data/lib/html_reporter.rb +0 -37
- data/lib/options.rb +0 -69
- data/lib/reporter.rb +0 -62
- data/lib/scenario.rb +0 -19
- data/lib/step.rb +0 -10
- data/lib/step_down.rb +0 -112
- data/lib/step_group.rb +0 -52
- data/lib/step_instance.rb +0 -60
- data/lib/step_usage.rb +0 -13
- data/lib/text_reporter.rb +0 -36
- data/spec/lib/scenario_spec.rb +0 -42
- data/spec/lib/step_group_spec.rb +0 -119
data/lib/counting_step.rb
DELETED
data/lib/feature_parser.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
require 'rubygems'
|
3
|
-
|
4
|
-
require File.expand_path(File.dirname(__FILE__) + '/step')
|
5
|
-
require File.expand_path(File.dirname(__FILE__) + '/scenario')
|
6
|
-
|
7
|
-
class FeatureParser
|
8
|
-
|
9
|
-
def process_feature(file, instance)
|
10
|
-
@scenarios = []
|
11
|
-
file_lines = read_feature_file(file)
|
12
|
-
|
13
|
-
file_lines.each do |line|
|
14
|
-
|
15
|
-
if line =~ /Scenario|Background/
|
16
|
-
@scenario = Scenario.new
|
17
|
-
@scenarios << @scenario
|
18
|
-
else
|
19
|
-
step = instance.line_matches(line)
|
20
|
-
@scenario.add_step(step) if step
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
return @scenarios
|
25
|
-
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
def read_feature_file(file_name)
|
29
|
-
File.read(file_name).split("\n")
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
data/lib/html_reporter.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'reporter'
|
3
|
-
class HTMLReporter < Reporter
|
4
|
-
|
5
|
-
def output_overview()
|
6
|
-
puts "Generating report..."
|
7
|
-
FileUtils.mkdir_p(Reporter::OUTPUT_DIR)
|
8
|
-
copy_files
|
9
|
-
|
10
|
-
template = File.open(File.expand_path(File.dirname(__FILE__)) + '/../templates/main.html.haml').read()
|
11
|
-
engine = Haml::Engine.new(template)
|
12
|
-
|
13
|
-
out = File.new(Reporter::OUTPUT_DIR + '/analysis.html','w+')
|
14
|
-
out.puts engine.render(self)
|
15
|
-
out.close
|
16
|
-
|
17
|
-
template = File.open(File.expand_path(File.dirname(__FILE__)) + '/../templates/style.sass').read
|
18
|
-
sass_engine = Sass::Engine.new(template)
|
19
|
-
|
20
|
-
out = File.new(Reporter::OUTPUT_DIR + '/style.css', 'w+')
|
21
|
-
out.puts sass_engine.render
|
22
|
-
|
23
|
-
out.close
|
24
|
-
|
25
|
-
$stdout.puts "\nReport output to #{Reporter::OUTPUT_DIR}/analysis.html"
|
26
|
-
end
|
27
|
-
|
28
|
-
protected
|
29
|
-
|
30
|
-
def copy_files
|
31
|
-
['step_down.js', 'jquery-1.4.3.min.js'].each do |file|
|
32
|
-
src = File.expand_path("#{File.dirname(__FILE__)}/../public/#{file}")
|
33
|
-
FileUtils.cp(src, File.join(OUTPUT_DIR, "#{file}"))
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
data/lib/options.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
|
-
class Options
|
4
|
-
|
5
|
-
OUTPUT_FORMATS = ["html", "text"]
|
6
|
-
|
7
|
-
def parse(params)
|
8
|
-
@@steps_dir = "features/step_definitions"
|
9
|
-
@@features_dir = "features"
|
10
|
-
@@reporter = "html"
|
11
|
-
parser = OptionParser.new do |opts|
|
12
|
-
opts.banner = "Usage: stepdown step_definition_dir feature_file_directory"
|
13
|
-
|
14
|
-
opts.separator("")
|
15
|
-
|
16
|
-
opts.on("--output=TYPE", OUTPUT_FORMATS, "Select ouput format (#{OUTPUT_FORMATS.join(',')}). Default: html") do |o|
|
17
|
-
@@reporter = o
|
18
|
-
end
|
19
|
-
|
20
|
-
opts.on("--steps=STEPS_DIR", "Step definition directory. Default: ./features/step_definitions") do |o|
|
21
|
-
@@steps_dir = o
|
22
|
-
end
|
23
|
-
|
24
|
-
opts.on("--features=FEATURE_DIR", "Feature file directory. Default: ./features") do |o|
|
25
|
-
@@features_dir = o
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on_tail("-h", "--help", "You're looking at it") do |o|
|
29
|
-
puts opts
|
30
|
-
exit
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
begin
|
36
|
-
parser.parse(params)
|
37
|
-
|
38
|
-
rescue OptionParser::ParseError => e
|
39
|
-
puts e
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def validate
|
45
|
-
@@steps_dir = File.join(Dir.pwd, @@steps_dir)
|
46
|
-
@@features_dir = File.join(Dir.pwd, @@features_dir)
|
47
|
-
|
48
|
-
[@@steps_dir, @@features_dir].each do |dir|
|
49
|
-
unless File.exists?(dir)
|
50
|
-
puts "Directory #{dir} does not exist"
|
51
|
-
exit 1
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
def steps_dir
|
58
|
-
@@steps_dir
|
59
|
-
end
|
60
|
-
|
61
|
-
def features_dir
|
62
|
-
@@features_dir
|
63
|
-
end
|
64
|
-
|
65
|
-
def reporter
|
66
|
-
@@reporter
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
data/lib/reporter.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
|
2
|
-
class Reporter
|
3
|
-
OUTPUT_DIR = "./stepdown"
|
4
|
-
|
5
|
-
attr_reader :scenarios, :usages, :steps, :grouping
|
6
|
-
|
7
|
-
def initialize(scenarios, usages, grouping, steps)
|
8
|
-
@scenarios = scenarios
|
9
|
-
@usages = usages
|
10
|
-
@steps = steps
|
11
|
-
@grouping = grouping
|
12
|
-
end
|
13
|
-
|
14
|
-
def groupings
|
15
|
-
@grouping
|
16
|
-
end
|
17
|
-
|
18
|
-
def total_scenarios
|
19
|
-
@scenarios.length
|
20
|
-
end
|
21
|
-
|
22
|
-
def total_steps
|
23
|
-
@steps.length
|
24
|
-
end
|
25
|
-
|
26
|
-
def steps_per_scenario
|
27
|
-
steps_scenario(@scenarios)
|
28
|
-
end
|
29
|
-
|
30
|
-
def unique_steps
|
31
|
-
uniq_steps_per_scenario(@scenarios)
|
32
|
-
end
|
33
|
-
|
34
|
-
def usages
|
35
|
-
@usages.select{|use| use.total_usage > 0 }
|
36
|
-
end
|
37
|
-
|
38
|
-
def unused_steps
|
39
|
-
@usages.select{|use| use.total_usage == 0}
|
40
|
-
end
|
41
|
-
|
42
|
-
def uniq_steps_per_scenario(scenarios)
|
43
|
-
total_steps = 0.0
|
44
|
-
uniq_steps = 0.0
|
45
|
-
scenarios.each do |scen|
|
46
|
-
total_steps += scen.steps.length
|
47
|
-
uniq_steps += scen.uniq_steps.length
|
48
|
-
end
|
49
|
-
sprintf "%.2f", (total_steps / uniq_steps)
|
50
|
-
end
|
51
|
-
|
52
|
-
def steps_scenario(scenarios)
|
53
|
-
scen_count = scenarios.length
|
54
|
-
step_count = 0.0
|
55
|
-
scenarios.each do |scenario|
|
56
|
-
step_count += scenario.steps.length
|
57
|
-
end
|
58
|
-
sprintf "%.2f", (step_count / scen_count)
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
|
data/lib/scenario.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
class Scenario
|
2
|
-
|
3
|
-
def add_step(step)
|
4
|
-
steps << step
|
5
|
-
end
|
6
|
-
|
7
|
-
def steps
|
8
|
-
@steps ||= []
|
9
|
-
end
|
10
|
-
|
11
|
-
def uniq_steps
|
12
|
-
uniq_steps = []
|
13
|
-
steps.each do |step|
|
14
|
-
uniq_steps << step unless uniq_steps.any?{|uniq| uniq.id == step.id}
|
15
|
-
end
|
16
|
-
uniq_steps
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
data/lib/step.rb
DELETED
data/lib/step_down.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
require 'feature_parser'
|
2
|
-
require 'pp'
|
3
|
-
require 'haml'
|
4
|
-
require 'sass'
|
5
|
-
|
6
|
-
require 'step_instance'
|
7
|
-
require 'step_group'
|
8
|
-
require 'step_usage'
|
9
|
-
require 'html_reporter'
|
10
|
-
require 'text_reporter'
|
11
|
-
class StepDown
|
12
|
-
|
13
|
-
def initialize(steps_dir, feature_dir, reporter)
|
14
|
-
@feature_files = Dir.glob(feature_dir + '/**/*.feature')
|
15
|
-
@step_files = Dir.glob(steps_dir + '/**/*.rb')
|
16
|
-
@reporter = reporter
|
17
|
-
end
|
18
|
-
|
19
|
-
def analyse
|
20
|
-
puts "Parsing feature files..."
|
21
|
-
parser = FeatureParser.new
|
22
|
-
|
23
|
-
scenarios = []
|
24
|
-
@feature_files.each do |feature|
|
25
|
-
scenarios << parser.process_feature(feature, instance)
|
26
|
-
end
|
27
|
-
scenarios.flatten!
|
28
|
-
|
29
|
-
puts "Performing analysis..."
|
30
|
-
usages = step_usage(scenarios)
|
31
|
-
usages = usages.sort{|a,b| b.total_usage <=> a.total_usage }
|
32
|
-
grouping = grouping(scenarios).sort{|a,b| b.use_count <=> a.use_count}
|
33
|
-
|
34
|
-
reporter = reporter(@reporter, scenarios, usages, grouping, instance.steps)
|
35
|
-
reporter.output_overview
|
36
|
-
|
37
|
-
# #pp grouping(@scenarios)
|
38
|
-
# puts YAML::dump(scenario) if scenario.use_count > 100 && scenario.use_count < 500
|
39
|
-
# end
|
40
|
-
end
|
41
|
-
|
42
|
-
# don't want a factory just yet
|
43
|
-
def reporter(type, scenarios, usages, grouping, steps)
|
44
|
-
case type
|
45
|
-
when "html"
|
46
|
-
HTMLReporter.new(scenarios, usages, grouping, steps)
|
47
|
-
when "text"
|
48
|
-
TextReporter.new(scenarios, usages, grouping, steps)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def step_usage(scenarios)
|
53
|
-
usages = instance.steps.collect{|step| StepUsage.new(step) }
|
54
|
-
scenarios.each do |scenario|
|
55
|
-
|
56
|
-
scenario.steps.each do |step|
|
57
|
-
usage = usages.detect{|use| use.step.id == step.id}
|
58
|
-
usage.total_usage += 1 if usage
|
59
|
-
end
|
60
|
-
|
61
|
-
scenario.uniq_steps.each do |step|
|
62
|
-
usage = usages.detect{|use| use.step.id == step.id}
|
63
|
-
usage.number_scenarios += 1 if usage
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
usages.each do |usage|
|
69
|
-
if usage.number_scenarios > 0
|
70
|
-
use = sprintf "%.2f", (usage.total_usage / Float(usage.number_scenarios))
|
71
|
-
usage.use_scenario = use
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
usages
|
76
|
-
end
|
77
|
-
|
78
|
-
def grouping(scenarios)
|
79
|
-
step_groups = instance.steps.collect{|step| StepGroup.new(step) }
|
80
|
-
|
81
|
-
step_groups.each do |step_group|
|
82
|
-
scenarios.each do |scenario|
|
83
|
-
used = scenario.steps.any?{|s| s.id == step_group.id}
|
84
|
-
|
85
|
-
if used
|
86
|
-
scenario.steps.each do |scen_step|
|
87
|
-
step_group.add_step(scen_step)
|
88
|
-
end
|
89
|
-
step_group.update_use_count
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
step_groups
|
96
|
-
end
|
97
|
-
|
98
|
-
def step(id)
|
99
|
-
instance.steps.detect{|step| step.id == id}
|
100
|
-
end
|
101
|
-
|
102
|
-
def instance
|
103
|
-
@instance ||= begin
|
104
|
-
new_inst = StepInstance.new
|
105
|
-
|
106
|
-
Dir.glob(@step_files).each do |file_name|
|
107
|
-
new_inst.instance_eval File.read(file_name)
|
108
|
-
end
|
109
|
-
new_inst
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
data/lib/step_group.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
require 'counting_step'
|
3
|
-
class StepGroup
|
4
|
-
attr_reader :id, :regex, :total_usage
|
5
|
-
|
6
|
-
def initialize(step)
|
7
|
-
@id = step.id
|
8
|
-
@regex = step.regex
|
9
|
-
@total_usage = 0
|
10
|
-
@in_steps = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
def in_steps
|
14
|
-
@in_steps.sort{|a,b| b[1] <=> a[1]}
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_step(step)
|
18
|
-
if @in_steps[step.id]
|
19
|
-
@in_steps[step.id].count += 1
|
20
|
-
else
|
21
|
-
@in_steps[step.id] = CountingStep.new(step.id, step.regex)
|
22
|
-
@in_steps[step.id].count = 1
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def update_use_count
|
27
|
-
@total_usage = 0
|
28
|
-
@in_steps.each do |key,val|
|
29
|
-
@total_usage += val.count
|
30
|
-
end
|
31
|
-
@total_usage
|
32
|
-
end
|
33
|
-
|
34
|
-
def use_count
|
35
|
-
@total_usage || 0
|
36
|
-
end
|
37
|
-
|
38
|
-
def group_graph
|
39
|
-
base = "https://chart.googleapis.com/chart?cht=gv:circo&chl=graph{"
|
40
|
-
base += "a [label=\"#{CGI.escape(CGI.escapeHTML(@regex.inspect.to_s))}\"];"
|
41
|
-
|
42
|
-
@in_steps.each do |id,in_step|
|
43
|
-
|
44
|
-
next if in_step[:step].regex.nil?
|
45
|
-
base += "a--\"#{CGI.escape(CGI.escapeHTML(in_step[:step].regex.inspect.to_s))}\" [weight=#{in_step[:count]}];"
|
46
|
-
#a [label=\"#{grouping.in_steps[0][:step].regex.inspect}\"]; a--b [penwidth=3,weight=2];b--d}"
|
47
|
-
end
|
48
|
-
base += "}"
|
49
|
-
base
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/lib/step_instance.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
class StepInstance
|
2
|
-
def initialize
|
3
|
-
@steps = []
|
4
|
-
end
|
5
|
-
|
6
|
-
def Given(regex,&block)
|
7
|
-
define_step(regex,&block)
|
8
|
-
end
|
9
|
-
|
10
|
-
def When(regex,&block)
|
11
|
-
define_step(regex,&block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def Then(regex,&block)
|
15
|
-
define_step(regex,&block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def define_step(regex,&block)
|
19
|
-
@steps << regex
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.method_missing(*args)
|
23
|
-
#nothing
|
24
|
-
end
|
25
|
-
|
26
|
-
def method_missing(*args)
|
27
|
-
#nothing
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.const_missing(*args)
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
def require(*args)
|
35
|
-
# do nothing
|
36
|
-
end
|
37
|
-
|
38
|
-
def line_matches(line)
|
39
|
-
stripped_line = line.strip.gsub(/^(And|Given|When|Then) (.*)$/,'\2')
|
40
|
-
|
41
|
-
@steps.each_with_index do |regex,i|
|
42
|
-
match = regex.match(stripped_line)
|
43
|
-
if match
|
44
|
-
return steps[i]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
return nil
|
49
|
-
end
|
50
|
-
|
51
|
-
def steps
|
52
|
-
return @step_definitions if @step_definitions
|
53
|
-
@step_definitions = []
|
54
|
-
@steps.each_with_index do |regex, i|
|
55
|
-
@step_definitions << Step.new(i, regex)
|
56
|
-
end
|
57
|
-
@step_definitions
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|