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.
Files changed (45) hide show
  1. data/Gemfile +4 -2
  2. data/Gemfile.lock +14 -10
  3. data/History.txt +30 -0
  4. data/README.rdoc +2 -2
  5. data/Rakefile +13 -0
  6. data/bin/stepdown +4 -4
  7. data/lib/stepdown.rb +6 -0
  8. data/lib/stepdown/analyzer.rb +67 -0
  9. data/lib/stepdown/feature_parser.rb +30 -0
  10. data/lib/stepdown/html_reporter.rb +41 -0
  11. data/lib/stepdown/options.rb +59 -0
  12. data/lib/stepdown/reporter.rb +106 -0
  13. data/lib/stepdown/scenario.rb +25 -0
  14. data/lib/stepdown/step.rb +22 -0
  15. data/lib/stepdown/step_collection.rb +36 -0
  16. data/lib/stepdown/step_group.rb +45 -0
  17. data/lib/stepdown/step_instance.rb +63 -0
  18. data/lib/stepdown/step_usage.rb +15 -0
  19. data/lib/stepdown/text_reporter.rb +38 -0
  20. data/spec/lib/{feature_parser_spec.rb → stepdown/feature_parser_spec.rb} +13 -12
  21. data/spec/lib/{options_spec.rb → stepdown/options_spec.rb} +24 -6
  22. data/spec/lib/stepdown/reporter_spec.rb +184 -0
  23. data/spec/lib/stepdown/scenario_spec.rb +40 -0
  24. data/spec/lib/stepdown/step_collection_spec.rb +78 -0
  25. data/spec/lib/stepdown/step_group_spec.rb +43 -0
  26. data/spec/lib/{step_instance_spec.rb → stepdown/step_instance_spec.rb} +13 -12
  27. data/spec/spec_helper.rb +4 -0
  28. data/stepdown.gemspec +7 -4
  29. data/templates/main.html.haml +3 -3
  30. data/templates/style.sass +5 -4
  31. metadata +64 -34
  32. data/lib/counting_step.rb +0 -14
  33. data/lib/feature_parser.rb +0 -32
  34. data/lib/html_reporter.rb +0 -37
  35. data/lib/options.rb +0 -69
  36. data/lib/reporter.rb +0 -62
  37. data/lib/scenario.rb +0 -19
  38. data/lib/step.rb +0 -10
  39. data/lib/step_down.rb +0 -112
  40. data/lib/step_group.rb +0 -52
  41. data/lib/step_instance.rb +0 -60
  42. data/lib/step_usage.rb +0 -13
  43. data/lib/text_reporter.rb +0 -36
  44. data/spec/lib/scenario_spec.rb +0 -42
  45. data/spec/lib/step_group_spec.rb +0 -119
data/Gemfile CHANGED
@@ -1,7 +1,9 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'haml'
3
+ gem 'haml', '> 2.0.0'
4
4
 
5
5
  group :development,:test do
6
- gem 'rspec'
6
+ gem 'rake'
7
+ gem 'rspec', '~> 2.5.0'
8
+ gem 'rcov', '~> 0.9.9'
7
9
  end
@@ -2,20 +2,24 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  diff-lcs (1.1.2)
5
- haml (3.0.25)
6
- rspec (2.4.0)
7
- rspec-core (~> 2.4.0)
8
- rspec-expectations (~> 2.4.0)
9
- rspec-mocks (~> 2.4.0)
10
- rspec-core (2.4.0)
11
- rspec-expectations (2.4.0)
5
+ haml (2.0.10)
6
+ rake (0.8.7)
7
+ rcov (0.9.9)
8
+ rspec (2.5.0)
9
+ rspec-core (~> 2.5.0)
10
+ rspec-expectations (~> 2.5.0)
11
+ rspec-mocks (~> 2.5.0)
12
+ rspec-core (2.5.1)
13
+ rspec-expectations (2.5.0)
12
14
  diff-lcs (~> 1.1.2)
13
- rspec-mocks (2.4.0)
15
+ rspec-mocks (2.5.0)
14
16
 
15
17
  PLATFORMS
16
18
  java
17
19
  ruby
18
20
 
19
21
  DEPENDENCIES
20
- haml
21
- rspec
22
+ haml (> 2.0.0)
23
+ rake
24
+ rcov (~> 0.9.9)
25
+ rspec (~> 2.5.0)
@@ -0,0 +1,30 @@
1
+ == 0.4.0 2011-3-29
2
+ * Better HTML output
3
+ * Structured like other gems
4
+ * Maintainability improvements
5
+ * Better test coverage
6
+
7
+ == 0.3.3 2011-03-05
8
+ * Better HTML output
9
+
10
+ == 0.3.2 - 2011-02-27
11
+ * Bugfix in option parsing
12
+ * Bugfix for missing constants
13
+
14
+ == 0.3.1 - 2011-02-26
15
+ * Fix broken include [Robert Postill]
16
+
17
+ == 0.3.0 - 2011-02-26
18
+ * Added text report
19
+ * Bug fix for missing constants
20
+
21
+ == 0.2.1 - 2011-02-19
22
+ * Proper option parsing
23
+
24
+ == 0.2 - 2011-02-14
25
+ * Added some specs
26
+ * Improved output
27
+ * Updated usage message
28
+
29
+ == 0.1 - 2011-01-16
30
+ * Initial release
@@ -17,5 +17,5 @@ Stepdown is available as a ruby gem
17
17
  gem install stepdown
18
18
 
19
19
  == Usage
20
- stepdown <step definition directory> <feature file directory>
21
- e.g. stepdown features/step_definitions features
20
+ stepdown --steps <step definition directory> --features <feature file directory>
21
+ e.g. stepdown --steps features/step_definitions --features features
@@ -0,0 +1,13 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec) do |t|
4
+ t.fail_on_error = false
5
+ end
6
+
7
+ RSpec::Core::RakeTask.new(:coverage) do |t|
8
+ t.fail_on_error = false
9
+ t.rcov_opts = %w{ --exclude gems\/,spec\/,features\/}
10
+ t.rcov = true
11
+ end
12
+
13
+ task :default => :spec
@@ -2,16 +2,16 @@
2
2
  lib = File.expand_path('../lib/', __FILE__)
3
3
  $:.unshift lib unless $:.include?(lib)
4
4
 
5
- require 'step_down'
6
- require 'options'
5
+ require 'stepdown'
6
+ require 'stepdown/options'
7
7
 
8
8
  begin
9
9
 
10
- options = Options.new
10
+ options = Stepdown::Options.new
11
11
  options.parse(ARGV)
12
12
  options.validate
13
13
 
14
- StepDown.new(options.steps_dir, options.features_dir, options.reporter).analyse
14
+ Stepdown::Analyzer.new(options.steps_dir, options.features_dir, options.reporter).analyse
15
15
 
16
16
  rescue Interrupt => e
17
17
  puts "Quiting..."
@@ -0,0 +1,6 @@
1
+ require 'stepdown/feature_parser'
2
+ require 'stepdown/step_instance'
3
+ require 'stepdown/html_reporter'
4
+ require 'stepdown/text_reporter'
5
+
6
+ require 'stepdown/analyzer'
@@ -0,0 +1,67 @@
1
+
2
+
3
+ module Stepdown
4
+ class Analyzer
5
+ def initialize(steps_dir, feature_dir, reporter)
6
+ @feature_dir = feature_dir
7
+ @steps_dir = steps_dir
8
+ @reporter = reporter
9
+ end
10
+
11
+ def analyse
12
+ puts "Parsing feature files..."
13
+ scenarios = process_feature_files(feature_files)
14
+
15
+ puts "Performing analysis..."
16
+
17
+ reporter = reporter(@reporter, scenarios, instance.step_collection)
18
+ reporter.output_overview
19
+
20
+ end
21
+
22
+ def process_feature_files(feature_files)
23
+ parser = Stepdown::FeatureParser.new
24
+
25
+ scenarios = []
26
+ feature_files.each do |feature_file|
27
+ scenarios << parser.process_feature(feature_file, instance)
28
+ end
29
+ scenarios.flatten
30
+ end
31
+
32
+ def reporter(type, scenarios, step_collection)
33
+ case type
34
+ when "html"
35
+ Stepdown::HTMLReporter.new(scenarios, step_collection)
36
+ when "text"
37
+ Stepdown::TextReporter.new(scenarios, step_collection)
38
+ end
39
+ end
40
+
41
+ def step(id)
42
+ instance.steps.detect{|step| step.id == id}
43
+ end
44
+
45
+ def instance
46
+ @instance ||= begin
47
+ new_inst = Stepdown::StepInstance.new
48
+
49
+ Dir.glob(step_files).each do |file_name|
50
+ new_inst.instance_eval File.read(file_name)
51
+ end
52
+ new_inst
53
+ end
54
+ end
55
+
56
+ private
57
+ def feature_files
58
+ return @feature_files if @feature_files
59
+ @feature_files = Dir.glob(@feature_dir + '/**/*.feature')
60
+ end
61
+
62
+ def step_files
63
+ return @step_files if @step_files
64
+ @step_files = Dir.glob(@steps_dir + '/**/*.rb')
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,30 @@
1
+ require 'stepdown/step'
2
+ require 'stepdown/scenario'
3
+ module Stepdown
4
+ class FeatureParser
5
+
6
+ def process_feature(file, instance)
7
+ scenarios = []
8
+ file_lines = read_feature_file(file)
9
+
10
+ file_lines.each do |line|
11
+
12
+ if line =~ /Scenario|Background/
13
+ @scenario = Scenario.new
14
+ scenarios << @scenario
15
+ else
16
+ step = instance.line_matches(line)
17
+ @scenario.add_step(step) if step
18
+ end
19
+ end
20
+
21
+ scenarios
22
+ end
23
+
24
+ protected
25
+ def read_feature_file(file_name)
26
+ File.read(file_name).split("\n")
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,41 @@
1
+ require 'fileutils'
2
+ require 'stepdown/reporter'
3
+ require 'haml'
4
+ require 'sass'
5
+
6
+ module Stepdown
7
+ class HTMLReporter < Reporter
8
+
9
+ def output_overview()
10
+ puts "Generating report..."
11
+ FileUtils.mkdir_p(Reporter::OUTPUT_DIR)
12
+ copy_files
13
+
14
+ template = File.open(File.expand_path(File.dirname(__FILE__)) + '/../../templates/main.html.haml').read()
15
+ engine = Haml::Engine.new(template)
16
+
17
+ out = File.new(Reporter::OUTPUT_DIR + '/analysis.html','w+')
18
+ out.puts engine.render(self)
19
+ out.close
20
+
21
+ template = File.open(File.expand_path(File.dirname(__FILE__)) + '/../../templates/style.sass').read
22
+ sass_engine = Sass::Engine.new(template)
23
+
24
+ out = File.new(Reporter::OUTPUT_DIR + '/style.css', 'w+')
25
+ out.puts sass_engine.render
26
+
27
+ out.close
28
+
29
+ $stdout.puts "\nReport output to #{Reporter::OUTPUT_DIR}/analysis.html"
30
+ end
31
+
32
+ protected
33
+
34
+ def copy_files
35
+ ['step_down.js', 'jquery-1.4.3.min.js'].each do |file|
36
+ src = File.expand_path("#{File.dirname(__FILE__)}/../../public/#{file}")
37
+ FileUtils.cp(src, File.join(OUTPUT_DIR, "#{file}"))
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,59 @@
1
+ require 'optparse'
2
+
3
+ module Stepdown
4
+ class Options
5
+ attr_reader :steps_dir, :features_dir, :reporter
6
+
7
+ OUTPUT_FORMATS = ["html", "text"]
8
+
9
+ def parse(params)
10
+ @steps_dir = "features/step_definitions"
11
+ @features_dir = "features"
12
+ @reporter = "html"
13
+ parser = OptionParser.new do |opts|
14
+ opts.banner = "Usage: stepdown step_definition_dir feature_file_directory"
15
+
16
+ opts.separator("")
17
+
18
+ opts.on("--output=TYPE", OUTPUT_FORMATS, "Select ouput format (#{OUTPUT_FORMATS.join(',')}). Default: html") do |o|
19
+ @reporter = o
20
+ end
21
+
22
+ opts.on("--steps=STEPS_DIR", "Step definition directory. Default: ./features/step_definitions") do |o|
23
+ @steps_dir = o
24
+ end
25
+
26
+ opts.on("--features=FEATURE_DIR", "Feature file directory. Default: ./features") do |o|
27
+ @features_dir = o
28
+ end
29
+
30
+ opts.on_tail("-h", "--help", "You're looking at it") do |o|
31
+ puts opts
32
+ exit
33
+ end
34
+
35
+ end
36
+
37
+ begin
38
+ parser.parse(params)
39
+
40
+ rescue OptionParser::ParseError => e
41
+ puts e
42
+ exit 1
43
+ end
44
+ end
45
+
46
+ def validate(io = STDOUT)
47
+ @steps_dir = File.join(Dir.pwd, @steps_dir)
48
+ @features_dir = File.join(Dir.pwd, @features_dir)
49
+
50
+ [@steps_dir, @features_dir].each do |dir|
51
+ unless File.exists?(dir)
52
+ io.puts "Directory #{dir} does not exist"
53
+ exit 1
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,106 @@
1
+ require 'stepdown/step_group'
2
+ require 'stepdown/step_usage'
3
+
4
+ module Stepdown
5
+ class Reporter
6
+ OUTPUT_DIR = "./stepdown"
7
+
8
+ attr_reader :scenarios, :usages, :step_collection, :grouping
9
+
10
+ def initialize(scenarios, step_collection)
11
+ @scenarios = scenarios
12
+ @step_collection = step_collection
13
+ end
14
+
15
+ def groupings
16
+ @groupings ||= grouping(@scenarios)
17
+ end
18
+
19
+ def total_scenarios
20
+ @scenarios.length
21
+ end
22
+
23
+ def total_steps
24
+ @step_collection.length
25
+ end
26
+
27
+ def steps_per_scenario
28
+ steps_scenario(@scenarios)
29
+ end
30
+
31
+ def unique_steps
32
+ uniq_steps_per_scenario(@scenarios)
33
+ end
34
+
35
+ def grouping(scenarios)
36
+ step_groups = @step_collection.collect{|step| Stepdown::StepGroup.new(step) }
37
+
38
+ step_groups.each do |step_group|
39
+ scenarios.each do |scenario|
40
+
41
+ if scenario.steps.any?{|step| step.id == step_group.id}
42
+ step_group.add_steps(scenario.steps)
43
+ step_group.update_use_count(scenario.step_count)
44
+ end
45
+ end
46
+
47
+ end
48
+ step_groups.sort{|a,b| b.use_count <=> a.use_count}
49
+ end
50
+
51
+ def step_usage(scenarios)
52
+ usages = @step_collection.collect{|step| Stepdown::StepUsage.new(step) }
53
+ scenarios.each do |scenario|
54
+
55
+ scenario.steps.each do |step|
56
+ usage = usages.detect{|use| use.step.id == step.id}
57
+ if usage
58
+ usage.total_usage += step.count
59
+ usage.number_scenarios += 1
60
+ end
61
+ end
62
+ end
63
+
64
+ usages.each do |usage|
65
+ if usage.number_scenarios > 0
66
+ use = sprintf "%.2f", (usage.total_usage / Float(usage.number_scenarios))
67
+ usage.use_scenario = use
68
+ end
69
+ end
70
+
71
+ usages.sort{|a,b| b.total_usage <=> a.total_usage}
72
+ end
73
+
74
+ def step_usages
75
+ @step_usages ||= step_usage(@scenarios)
76
+ end
77
+
78
+ def usages
79
+ step_usages.select{|use| use.total_usage > 0 }
80
+ end
81
+
82
+ def unused_steps
83
+ step_usages.select{|use| use.total_usage == 0}
84
+ end
85
+
86
+ def uniq_steps_per_scenario(scenarios)
87
+ total_steps = 0.0
88
+ uniq_steps = 0.0
89
+ scenarios.each do |scen|
90
+ total_steps += scen.step_count
91
+ uniq_steps += scen.unique_step_count
92
+ end
93
+ sprintf "%.2f", (total_steps / uniq_steps)
94
+ end
95
+
96
+ def steps_scenario(scenarios)
97
+ scen_count = scenarios.length
98
+ step_count = 0.0
99
+ scenarios.each do |scenario|
100
+ step_count += scenario.step_count
101
+ end
102
+ sprintf "%.2f", (step_count / scen_count)
103
+ end
104
+ end
105
+ end
106
+
@@ -0,0 +1,25 @@
1
+ require 'stepdown/step_collection'
2
+
3
+ module Stepdown
4
+ class Scenario
5
+ attr_reader :step_count
6
+ def initialize
7
+ @step_collection = Stepdown::StepCollection.new
8
+ @step_count = 0
9
+ end
10
+
11
+ def add_step(step)
12
+ @step_count += 1
13
+ @step_collection.add_step(step.id, step.regex)
14
+ end
15
+
16
+ def steps
17
+ @step_collection.steps
18
+ end
19
+
20
+ def unique_step_count
21
+ @step_collection.length
22
+ end
23
+
24
+ end
25
+ end