stepdown 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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