stepdown 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/stepdown +4 -3
- data/lib/feature_parser.rb +8 -4
- data/lib/options.rb +5 -5
- data/lib/reporter.rb +2 -2
- data/lib/step_down.rb +2 -1
- data/lib/step_group.rb +1 -2
- data/lib/step_instance.rb +6 -2
- data/public/step_down.js +5 -0
- data/spec/lib/feature_parser_spec.rb +85 -0
- data/spec/lib/options_spec.rb +21 -20
- data/spec/lib/scenario_spec.rb +42 -0
- data/spec/lib/step_instance_spec.rb +60 -2
- data/stepdown.gemspec +1 -1
- data/templates/main.html.haml +16 -7
- metadata +6 -4
data/bin/stepdown
CHANGED
@@ -7,10 +7,11 @@ require 'options'
|
|
7
7
|
|
8
8
|
begin
|
9
9
|
|
10
|
-
Options.
|
11
|
-
|
10
|
+
options = Options.new
|
11
|
+
options.parse(ARGV)
|
12
|
+
options.validate
|
12
13
|
|
13
|
-
StepDown.new(
|
14
|
+
StepDown.new(options.steps_dir, options.features_dir, options.reporter).analyse
|
14
15
|
|
15
16
|
rescue Interrupt => e
|
16
17
|
puts "Quiting..."
|
data/lib/feature_parser.rb
CHANGED
@@ -8,21 +8,25 @@ class FeatureParser
|
|
8
8
|
|
9
9
|
def process_feature(file, instance)
|
10
10
|
@scenarios = []
|
11
|
+
file_lines = read_feature_file(file)
|
11
12
|
|
12
|
-
|
13
|
-
@line_no = line_no
|
13
|
+
file_lines.each do |line|
|
14
14
|
|
15
15
|
if line =~ /Scenario|Background/
|
16
16
|
@scenario = Scenario.new
|
17
17
|
@scenarios << @scenario
|
18
18
|
else
|
19
|
-
|
20
|
-
@scenario.add_step(
|
19
|
+
step = instance.line_matches(line)
|
20
|
+
@scenario.add_step(step) if step
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
return @scenarios
|
25
25
|
end
|
26
26
|
|
27
|
+
protected
|
28
|
+
def read_feature_file(file_name)
|
29
|
+
File.read(file_name).split("\n")
|
30
|
+
end
|
27
31
|
end
|
28
32
|
|
data/lib/options.rb
CHANGED
@@ -4,7 +4,7 @@ class Options
|
|
4
4
|
|
5
5
|
OUTPUT_FORMATS = ["html", "text"]
|
6
6
|
|
7
|
-
def
|
7
|
+
def parse(params)
|
8
8
|
@@steps_dir = "features/step_definitions"
|
9
9
|
@@features_dir = "features"
|
10
10
|
@@reporter = "html"
|
@@ -41,7 +41,7 @@ class Options
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def validate
|
45
45
|
@@steps_dir = File.join(Dir.pwd, @@steps_dir)
|
46
46
|
@@features_dir = File.join(Dir.pwd, @@features_dir)
|
47
47
|
|
@@ -54,15 +54,15 @@ class Options
|
|
54
54
|
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
57
|
+
def steps_dir
|
58
58
|
@@steps_dir
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
61
|
+
def features_dir
|
62
62
|
@@features_dir
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
65
|
+
def reporter
|
66
66
|
@@reporter
|
67
67
|
end
|
68
68
|
|
data/lib/reporter.rb
CHANGED
@@ -46,7 +46,7 @@ class Reporter
|
|
46
46
|
total_steps += scen.steps.length
|
47
47
|
uniq_steps += scen.uniq_steps.length
|
48
48
|
end
|
49
|
-
total_steps / uniq_steps
|
49
|
+
sprintf "%.2f", (total_steps / uniq_steps)
|
50
50
|
end
|
51
51
|
|
52
52
|
def steps_scenario(scenarios)
|
@@ -55,7 +55,7 @@ class Reporter
|
|
55
55
|
scenarios.each do |scenario|
|
56
56
|
step_count += scenario.steps.length
|
57
57
|
end
|
58
|
-
step_count / scen_count
|
58
|
+
sprintf "%.2f", (step_count / scen_count)
|
59
59
|
end
|
60
60
|
|
61
61
|
end
|
data/lib/step_down.rb
CHANGED
@@ -67,7 +67,8 @@ class StepDown
|
|
67
67
|
|
68
68
|
usages.each do |usage|
|
69
69
|
if usage.number_scenarios > 0
|
70
|
-
|
70
|
+
use = sprintf "%.2f", (usage.total_usage / Float(usage.number_scenarios))
|
71
|
+
usage.use_scenario = use
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
data/lib/step_group.rb
CHANGED
data/lib/step_instance.rb
CHANGED
@@ -19,19 +19,23 @@ class StepInstance
|
|
19
19
|
@steps << regex
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.method_missing(*args)
|
23
|
+
#nothing
|
24
|
+
end
|
25
|
+
|
22
26
|
def method_missing(*args)
|
23
27
|
#nothing
|
24
28
|
end
|
25
29
|
|
26
30
|
def self.const_missing(*args)
|
27
|
-
|
31
|
+
self
|
28
32
|
end
|
29
33
|
|
30
34
|
def require(*args)
|
31
35
|
# do nothing
|
32
36
|
end
|
33
37
|
|
34
|
-
def line_matches(line
|
38
|
+
def line_matches(line)
|
35
39
|
stripped_line = line.strip.gsub(/^(And|Given|When|Then) (.*)$/,'\2')
|
36
40
|
|
37
41
|
@steps.each_with_index do |regex,i|
|
data/public/step_down.js
CHANGED
@@ -9,6 +9,11 @@ $(document).ready(function(){
|
|
9
9
|
$("#scenario_filter").change(function(){
|
10
10
|
filter(this.options[this.selectedIndex].value, 2, $("#usages tr"));
|
11
11
|
});
|
12
|
+
|
13
|
+
$("a[class*=g]").click(function() {
|
14
|
+
$('.' + this.getAttribute("class")).show();
|
15
|
+
return false;
|
16
|
+
});
|
12
17
|
});
|
13
18
|
|
14
19
|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/scenario')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/feature_parser')
|
3
|
+
|
4
|
+
describe FeatureParser do
|
5
|
+
def stub_line_match_with(instance, line, value)
|
6
|
+
instance.stub!(:line_matches).with(line).and_return(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "creating scenarios" do
|
10
|
+
before :each do
|
11
|
+
end
|
12
|
+
it "should create a scenario for a scenario line" do
|
13
|
+
|
14
|
+
file = mock("file")
|
15
|
+
instance = mock("instance")
|
16
|
+
file_lines = ["Scenario: My testing scenario"]
|
17
|
+
|
18
|
+
@parser = FeatureParser.new
|
19
|
+
@parser.should_receive(:read_feature_file).with(file).and_return(file_lines)
|
20
|
+
scenario = mock("scenario")
|
21
|
+
Scenario.should_receive(:new).and_return(scenario)
|
22
|
+
|
23
|
+
@parser.process_feature(file, instance).should =~ [scenario]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create a scenario for a background line" do
|
27
|
+
file = mock("file")
|
28
|
+
instance = mock("instance")
|
29
|
+
file_lines = ["Background: My testing scenario"]
|
30
|
+
|
31
|
+
@parser = FeatureParser.new
|
32
|
+
@parser.should_receive(:read_feature_file).with(file).and_return(file_lines)
|
33
|
+
scenario = mock("scenario")
|
34
|
+
Scenario.should_receive(:new).and_return(scenario)
|
35
|
+
|
36
|
+
@parser.process_feature(file, instance).should =~ [scenario]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
describe "parsing step lines" do
|
42
|
+
before :each do
|
43
|
+
@parser = FeatureParser.new
|
44
|
+
@step_instance = mock("step_instance")
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not add unmatched steps" do
|
49
|
+
lines = ["Scenario", "matched", "match 2"]
|
50
|
+
unmatched_lines = ["not matched", "not matched 2"]
|
51
|
+
steps = []
|
52
|
+
lines.each_with_index do |line, i|
|
53
|
+
step = Step.new(i, line)
|
54
|
+
stub_line_match_with(@step_instance, line, step)
|
55
|
+
steps << step
|
56
|
+
end
|
57
|
+
|
58
|
+
unmatched_lines.each do |line|
|
59
|
+
stub_line_match_with(@step_instance, line, nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
all_lines = [lines, unmatched_lines].flatten
|
63
|
+
@parser.should_receive(:read_feature_file).and_return(all_lines)
|
64
|
+
|
65
|
+
scenarios = @parser.process_feature(mock('file'), @step_instance)
|
66
|
+
scenarios.first.steps.should =~ steps[1..2]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should add matched steps" do
|
70
|
+
lines = ["Scenario", "matched", "match 2"]
|
71
|
+
steps = []
|
72
|
+
lines.each_with_index do |line, i|
|
73
|
+
step = Step.new(i, line)
|
74
|
+
stub_line_match_with(@step_instance, line, step)
|
75
|
+
steps << step
|
76
|
+
end
|
77
|
+
@parser.should_receive(:read_feature_file).and_return(lines)
|
78
|
+
|
79
|
+
scenarios = @parser.process_feature(mock('file'), @step_instance)
|
80
|
+
scenarios.first.steps.should =~ steps[1..2]
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/spec/lib/options_spec.rb
CHANGED
@@ -1,66 +1,67 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/../../lib/options')
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe @options do
|
5
5
|
|
6
6
|
before :each do
|
7
|
+
@options = Options.new
|
7
8
|
end
|
8
9
|
|
9
10
|
describe "setting input directories" do
|
10
11
|
it "should allow setting only steps directory" do
|
11
|
-
|
12
|
+
@options.parse(["--steps=step_dir"])
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
@options.steps_dir.should == "step_dir"
|
15
|
+
@options.features_dir.should == "features"
|
15
16
|
|
16
17
|
end
|
17
18
|
|
18
19
|
it "should allow setting only features directory" do
|
19
|
-
|
20
|
+
@options.parse(["--features=features_dir"])
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
@options.steps_dir.should == "features/step_definitions"
|
23
|
+
@options.features_dir.should == "features_dir"
|
23
24
|
end
|
24
25
|
|
25
26
|
it "should allow setting features and settings directory" do
|
26
|
-
|
27
|
+
@options.parse(["--features=features_dir", "--steps=steps_dir"])
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
@options.steps_dir.should == "steps_dir"
|
30
|
+
@options.features_dir.should == "features_dir"
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
describe "selecting reporter" do
|
34
35
|
it "should select html by default" do
|
35
|
-
|
36
|
+
@options.parse([])
|
36
37
|
|
37
|
-
|
38
|
+
@options.reporter.should == "html"
|
38
39
|
end
|
39
40
|
|
40
41
|
it "should allow selecting html" do
|
41
|
-
|
42
|
+
@options.parse(["--output=html"])
|
42
43
|
|
43
|
-
|
44
|
+
@options.reporter.should == "html"
|
44
45
|
end
|
45
46
|
|
46
47
|
it "should allow selecting text" do
|
47
|
-
|
48
|
+
@options.parse(["--output=text"])
|
48
49
|
|
49
|
-
|
50
|
+
@options.reporter.should == "text"
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
54
|
describe "using default directories" do
|
54
55
|
it "should select relative step directory" do
|
55
|
-
|
56
|
+
@options.parse([])
|
56
57
|
|
57
|
-
|
58
|
+
@options.steps_dir == "features/step_definitions"
|
58
59
|
end
|
59
60
|
|
60
61
|
it "should select relative feature directory" do
|
61
|
-
|
62
|
+
@options.parse([])
|
62
63
|
|
63
|
-
|
64
|
+
@options.features_dir.should == "features"
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/scenario')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/step')
|
3
|
+
|
4
|
+
|
5
|
+
describe Scenario do
|
6
|
+
before :each do
|
7
|
+
@scenario = Scenario.new
|
8
|
+
@s1 = Step.new(1, /step 1/)
|
9
|
+
@s2 = Step.new(2, /Step 2/)
|
10
|
+
@s2_dup = Step.new(2, /Step 2/)
|
11
|
+
@s3 = Step.new(3, /Step 3/)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "adding steps" do
|
16
|
+
it "should add steps to cache" do
|
17
|
+
@scenario.add_step(@s1)
|
18
|
+
@scenario.add_step(@s2)
|
19
|
+
@scenario.add_step(@s2_dup)
|
20
|
+
@scenario.add_step(@s3)
|
21
|
+
|
22
|
+
steps = [@s1, @s2, @s2_dup, @s3]
|
23
|
+
@scenario.steps.should =~ steps
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "returning unique steps" do
|
29
|
+
it "should only return one instance of each step" do
|
30
|
+
@scenario.add_step(@s1)
|
31
|
+
@scenario.add_step(@s2)
|
32
|
+
@scenario.add_step(@s2_dup)
|
33
|
+
@scenario.add_step(@s3)
|
34
|
+
|
35
|
+
steps = [@s1, @s2, @s3]
|
36
|
+
@scenario.uniq_steps.should =~ steps
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/../../lib/step_instance')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/step')
|
3
4
|
|
4
5
|
|
5
6
|
describe StepInstance do
|
@@ -10,17 +11,74 @@ describe StepInstance do
|
|
10
11
|
|
11
12
|
it "should deal with missing constants" do
|
12
13
|
lambda{ @step_instance.instance_eval("MissingConst") }.should_not raise_error
|
14
|
+
lambda{ @step_instance.instance_eval("MissingConst::MissingClass") }.should_not raise_error
|
15
|
+
lambda{ @step_instance.instance_eval("MissingConst::MissingClass.missing_method") }.should_not raise_error
|
13
16
|
end
|
17
|
+
|
14
18
|
it "should deal with missing methods" do
|
15
19
|
lambda{ @step_instance.doesnt_exist }.should_not raise_error
|
20
|
+
lambda{ StepInstance.doesnt_exist }.should_not raise_error
|
16
21
|
end
|
17
22
|
|
18
|
-
describe "steps" do
|
23
|
+
describe "returning steps" do
|
24
|
+
it "should return parsed steps" do
|
25
|
+
@step_instance.Given(/given/)
|
26
|
+
@step_instance.When(/when/)
|
27
|
+
@step_instance.Then(/then/)
|
28
|
+
|
29
|
+
@step_instance.steps.length.should == 3
|
30
|
+
end
|
19
31
|
|
20
32
|
end
|
21
33
|
|
22
|
-
describe "
|
34
|
+
describe "returning matched steps" do
|
35
|
+
it "should return nil when no matching step found" do
|
36
|
+
@step_instance.Given(/some step/)
|
37
|
+
@step_instance.line_matches("Given some other step").should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should parse And steps" do
|
41
|
+
@step_instance.Given(/matched step/)
|
42
|
+
@step_instance.line_matches("And matched step").regex.should == /matched step/
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should parse Given steps" do
|
46
|
+
@step_instance.Given(/matched step/)
|
47
|
+
@step_instance.line_matches("Given matched step").regex.should == /matched step/
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should parse When steps" do
|
51
|
+
@step_instance.When(/matched step/)
|
52
|
+
@step_instance.line_matches("When matched step").regex.should == /matched step/
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should parse Then steps" do
|
56
|
+
@step_instance.Then(/matched step/)
|
57
|
+
@step_instance.line_matches("Then matched step").regex.should == /matched step/
|
58
|
+
end
|
23
59
|
|
24
60
|
end
|
61
|
+
|
62
|
+
describe "parsing step definitions" do
|
63
|
+
before :each do
|
64
|
+
@regex = /reg/
|
65
|
+
@step = mock('step')
|
66
|
+
Step.should_receive(:new).with(0, @regex).and_return(@step)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should define given steps" do
|
70
|
+
@step_instance.Given(@regex)
|
71
|
+
@step_instance.steps.should =~ [@step]
|
72
|
+
end
|
25
73
|
|
74
|
+
it "should define when steps" do
|
75
|
+
@step_instance.When(@regex)
|
76
|
+
@step_instance.steps.should =~ [@step]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should define then steps" do
|
80
|
+
@step_instance.Then(@regex)
|
81
|
+
@step_instance.steps.should =~ [@step]
|
82
|
+
end
|
83
|
+
end
|
26
84
|
end
|
data/stepdown.gemspec
CHANGED
data/templates/main.html.haml
CHANGED
@@ -96,14 +96,23 @@
|
|
96
96
|
%tbody
|
97
97
|
%th Step
|
98
98
|
%th Total step associations
|
99
|
-
%th
|
100
99
|
|
101
|
-
- groupings.
|
100
|
+
- groupings.each_with_index do |grouping, i|
|
101
|
+
- next if grouping.use_count == 0
|
102
102
|
%tr
|
103
|
-
%td
|
103
|
+
%td
|
104
|
+
= grouping.regex.inspect
|
105
|
+
%br
|
106
|
+
%a{:href => '#', :class => "g#{i}"}Show associated steps
|
104
107
|
%td= grouping.use_count
|
105
|
-
%tr
|
108
|
+
%tr{:class => "g#{i}", :style => "display: none;"}
|
106
109
|
%td{:colspan => 2}
|
107
|
-
|
108
|
-
%
|
109
|
-
|
110
|
+
%table
|
111
|
+
%tr
|
112
|
+
%th Association count
|
113
|
+
%th Step
|
114
|
+
%tbody
|
115
|
+
- grouping.in_steps.each do |step|
|
116
|
+
%tr
|
117
|
+
%td= step[1].count
|
118
|
+
%td= CGI.escapeHTML step[1].regex.inspect
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stepdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 3
|
10
|
+
version: 0.3.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sean Caffery
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-03-06 00:00:00 +11:00
|
19
19
|
default_executable: stepdown
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -79,7 +79,9 @@ files:
|
|
79
79
|
- lib/text_reporter.rb
|
80
80
|
- public/jquery-1.4.3.min.js
|
81
81
|
- public/step_down.js
|
82
|
+
- spec/lib/feature_parser_spec.rb
|
82
83
|
- spec/lib/options_spec.rb
|
84
|
+
- spec/lib/scenario_spec.rb
|
83
85
|
- spec/lib/step_group_spec.rb
|
84
86
|
- spec/lib/step_instance_spec.rb
|
85
87
|
- stepdown.gemspec
|