jeffrafter-cucumber 0.1.10
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/History.txt +262 -0
- data/License.txt +20 -0
- data/Manifest.txt +241 -0
- data/README.txt +41 -0
- data/Rakefile +8 -0
- data/TODO.txt +26 -0
- data/bin/cucumber +6 -0
- data/config/hoe.rb +69 -0
- data/config/requirements.rb +15 -0
- data/cucumber.yml +1 -0
- data/examples/calculator_ruby_features/Rakefile +6 -0
- data/examples/calculator_ruby_features/features/addition.rb +23 -0
- data/examples/calculator_ruby_features/features/step_definitons/calculator_steps.rb +43 -0
- data/examples/cs/README.textile +22 -0
- data/examples/cs/Rakefile +12 -0
- data/examples/cs/features/hello.feature +11 -0
- data/examples/cs/features/step_definitons/hello_steps.rb +25 -0
- data/examples/cs/features/step_definitons/tree_steps.rb +14 -0
- data/examples/cs/features/tree.feature +9 -0
- data/examples/cs/src/Hello.cs +18 -0
- data/examples/dos_line_endings/Rakefile +6 -0
- data/examples/dos_line_endings/features/dos_line_endings.feature +9 -0
- data/examples/i18n/README.textile +18 -0
- data/examples/i18n/Rakefile +16 -0
- data/examples/i18n/ar/Rakefile +6 -0
- data/examples/i18n/ar/features/addition.feature +17 -0
- data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +32 -0
- data/examples/i18n/ar/lib/calculator.rb +10 -0
- data/examples/i18n/da/Rakefile +6 -0
- data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/da/features/summering.feature +17 -0
- data/examples/i18n/da/lib/kalkulator.rb +11 -0
- data/examples/i18n/de/Rakefile +6 -0
- data/examples/i18n/de/features/addition.feature +17 -0
- data/examples/i18n/de/features/division.feature +10 -0
- data/examples/i18n/de/features/step_definitons/calculator_steps.rb +30 -0
- data/examples/i18n/de/lib/calculator.rb +14 -0
- data/examples/i18n/en/Rakefile +6 -0
- data/examples/i18n/en/features/addition.feature +17 -0
- data/examples/i18n/en/features/division.feature +10 -0
- data/examples/i18n/en/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/en/lib/calculator.rb +14 -0
- data/examples/i18n/es/Rakefile +6 -0
- data/examples/i18n/es/features/adicion.feature +17 -0
- data/examples/i18n/es/features/step_definitons/calculador_steps.rb +22 -0
- data/examples/i18n/es/lib/calculador.rb +11 -0
- data/examples/i18n/et/Rakefile +6 -0
- data/examples/i18n/et/features/liitmine.feature +17 -0
- data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +26 -0
- data/examples/i18n/et/lib/kalkulaator.rb +10 -0
- data/examples/i18n/fr/Rakefile +6 -0
- data/examples/i18n/fr/features/addition.feature +13 -0
- data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +22 -0
- data/examples/i18n/fr/lib/calculatrice.rb +10 -0
- data/examples/i18n/id/Rakefile +6 -0
- data/examples/i18n/id/features/addition.feature +17 -0
- data/examples/i18n/id/features/division.feature +10 -0
- data/examples/i18n/id/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/id/lib/calculator.rb +14 -0
- data/examples/i18n/it/Rakefile +6 -0
- data/examples/i18n/it/features/somma.feature +10 -0
- data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +22 -0
- data/examples/i18n/it/lib/calcolatrice.rb +11 -0
- data/examples/i18n/ja/README.txt +5 -0
- data/examples/i18n/ja/Rakefile +6 -0
- data/examples/i18n/ja/features/addition.feature +17 -0
- data/examples/i18n/ja/features/division.feature +10 -0
- data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +30 -0
- data/examples/i18n/ja/lib/calculator.rb +14 -0
- data/examples/i18n/lt/Rakefile +6 -0
- data/examples/i18n/lt/features/addition.feature +17 -0
- data/examples/i18n/lt/features/division.feature +10 -0
- data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/lt/lib/calculator.rb +14 -0
- data/examples/i18n/no/Rakefile +6 -0
- data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/no/features/summering.feature +17 -0
- data/examples/i18n/no/lib/kalkulator.rb +11 -0
- data/examples/i18n/pt/Rakefile +6 -0
- data/examples/i18n/pt/features/adicao.feature +10 -0
- data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +22 -0
- data/examples/i18n/pt/lib/calculadora.rb +10 -0
- data/examples/i18n/ro/Rakefile +6 -0
- data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +22 -0
- data/examples/i18n/ro/features/suma.feature +10 -0
- data/examples/i18n/ro/lib/calculator.rb +11 -0
- data/examples/i18n/se/Rakefile +6 -0
- data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/se/features/summering.feature +17 -0
- data/examples/i18n/se/lib/kalkulator.rb +11 -0
- data/examples/i18n/zh-CN/Rakefile +6 -0
- data/examples/i18n/zh-CN/features/addition.feature +17 -0
- data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +24 -0
- data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
- data/examples/java/README.textile +22 -0
- data/examples/java/Rakefile +12 -0
- data/examples/java/features/hello.feature +11 -0
- data/examples/java/features/step_definitons/hello_steps.rb +25 -0
- data/examples/java/features/step_definitons/tree_steps.rb +14 -0
- data/examples/java/features/tree.feature +9 -0
- data/examples/java/src/cucumber/demo/Hello.java +16 -0
- data/examples/selenium/Rakefile +6 -0
- data/examples/selenium/features/search.feature +9 -0
- data/examples/selenium/features/step_definitons/stories_steps.rb +41 -0
- data/examples/test_unit/Rakefile +6 -0
- data/examples/test_unit/features/step_definitions/test_unit_steps.rb +26 -0
- data/examples/test_unit/features/test_unit.feature +9 -0
- data/examples/tickets/Rakefile +11 -0
- data/examples/tickets/cucumber.yml +2 -0
- data/examples/tickets/features/step_definitons/tickets_steps.rb +32 -0
- data/examples/tickets/features/tickets.feature +24 -0
- data/examples/watir/Rakefile +6 -0
- data/examples/watir/features/search.feature +9 -0
- data/examples/watir/features/step_definitons/stories_steps.rb +51 -0
- data/features/see_features.feature +8 -0
- data/features/steps/features_steps.rb +9 -0
- data/gem_tasks/deployment.rake +34 -0
- data/gem_tasks/environment.rake +7 -0
- data/gem_tasks/features.rake +6 -0
- data/gem_tasks/fix_cr_lf.rake +10 -0
- data/gem_tasks/flog.rake +4 -0
- data/gem_tasks/gemspec.rake +6 -0
- data/gem_tasks/rspec.rake +35 -0
- data/gem_tasks/treetop.rake +41 -0
- data/lib/autotest/cucumber.rb +6 -0
- data/lib/autotest/cucumber_mixin.rb +109 -0
- data/lib/autotest/cucumber_rails.rb +6 -0
- data/lib/autotest/cucumber_rails_rspec.rb +6 -0
- data/lib/autotest/cucumber_rspec.rb +6 -0
- data/lib/autotest/discover.rb +9 -0
- data/lib/cucumber/broadcaster.rb +20 -0
- data/lib/cucumber/cli.rb +303 -0
- data/lib/cucumber/core_ext/proc.rb +69 -0
- data/lib/cucumber/core_ext/string.rb +28 -0
- data/lib/cucumber/executor.rb +190 -0
- data/lib/cucumber/formatters/ansicolor.rb +109 -0
- data/lib/cucumber/formatters/autotest_formatter.rb +23 -0
- data/lib/cucumber/formatters/cucumber.css +132 -0
- data/lib/cucumber/formatters/cucumber.js +11 -0
- data/lib/cucumber/formatters/html_formatter.rb +128 -0
- data/lib/cucumber/formatters/jquery.js +32 -0
- data/lib/cucumber/formatters/pretty_formatter.rb +234 -0
- data/lib/cucumber/formatters/profile_formatter.rb +92 -0
- data/lib/cucumber/formatters/progress_formatter.rb +58 -0
- data/lib/cucumber/formatters.rb +1 -0
- data/lib/cucumber/languages.yml +258 -0
- data/lib/cucumber/model/table.rb +28 -0
- data/lib/cucumber/model.rb +1 -0
- data/lib/cucumber/platform.rb +12 -0
- data/lib/cucumber/rails/rspec.rb +12 -0
- data/lib/cucumber/rails/world.rb +73 -0
- data/lib/cucumber/rake/task.rb +101 -0
- data/lib/cucumber/step_methods.rb +49 -0
- data/lib/cucumber/step_mother.rb +95 -0
- data/lib/cucumber/tree/feature.rb +63 -0
- data/lib/cucumber/tree/features.rb +21 -0
- data/lib/cucumber/tree/given_scenario.rb +13 -0
- data/lib/cucumber/tree/scenario.rb +174 -0
- data/lib/cucumber/tree/step.rb +134 -0
- data/lib/cucumber/tree/table.rb +26 -0
- data/lib/cucumber/tree/top_down_visitor.rb +23 -0
- data/lib/cucumber/tree.rb +18 -0
- data/lib/cucumber/treetop_parser/feature.treetop.erb +206 -0
- data/lib/cucumber/treetop_parser/feature_ar.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_cy.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_da.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_de.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_en-tx.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_en.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_es.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_et.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_fr.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_id.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_it.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ja.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_lt.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_nl.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_no.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_parser.rb +34 -0
- data/lib/cucumber/treetop_parser/feature_pl.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_pt.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ro.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ro2.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ru.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_se.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_zh-CN.rb +1591 -0
- data/lib/cucumber/version.rb +9 -0
- data/lib/cucumber.rb +38 -0
- data/rails_generators/cucumber/USAGE +11 -0
- data/rails_generators/cucumber/cucumber_generator.rb +30 -0
- data/rails_generators/cucumber/templates/cucumber +7 -0
- data/rails_generators/cucumber/templates/cucumber.rake +7 -0
- data/rails_generators/cucumber/templates/env.rb +8 -0
- data/rails_generators/cucumber/templates/webrat_steps.rb +95 -0
- data/rails_generators/feature/USAGE +12 -0
- data/rails_generators/feature/feature_generator.rb +16 -0
- data/rails_generators/feature/templates/feature.erb +28 -0
- data/rails_generators/feature/templates/steps.erb +22 -0
- data/script/console +10 -0
- data/script/console.cmd +1 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/script/txt2html +74 -0
- data/script/txt2html.cmd +1 -0
- data/setup.rb +1585 -0
- data/spec/cucumber/broadcaster_spec.rb +27 -0
- data/spec/cucumber/cli_spec.rb +412 -0
- data/spec/cucumber/core_ext/proc_spec.rb +45 -0
- data/spec/cucumber/core_ext/string_spec.rb +34 -0
- data/spec/cucumber/executor_spec.rb +298 -0
- data/spec/cucumber/formatters/ansicolor_spec.rb +35 -0
- data/spec/cucumber/formatters/autotest_formatter_spec.rb +26 -0
- data/spec/cucumber/formatters/features.html +269 -0
- data/spec/cucumber/formatters/html_formatter_spec.rb +74 -0
- data/spec/cucumber/formatters/pretty_formatter_spec.rb +204 -0
- data/spec/cucumber/formatters/profile_formatter_spec.rb +192 -0
- data/spec/cucumber/formatters/progress_formatter_spec.rb +65 -0
- data/spec/cucumber/model/table_spec.rb +20 -0
- data/spec/cucumber/rails/stubs/mini_rails.rb +17 -0
- data/spec/cucumber/rails/stubs/test_help.rb +1 -0
- data/spec/cucumber/rails/world_spec.rb +11 -0
- data/spec/cucumber/sell_cucumbers.feature +19 -0
- data/spec/cucumber/step_mother_spec.rb +74 -0
- data/spec/cucumber/tree/feature_spec.rb +43 -0
- data/spec/cucumber/tree/row_scenario_spec.rb +55 -0
- data/spec/cucumber/tree/scenario_spec.rb +76 -0
- data/spec/cucumber/tree/step_spec.rb +50 -0
- data/spec/cucumber/treetop_parser/empty_feature.feature +4 -0
- data/spec/cucumber/treetop_parser/empty_scenario.feature +9 -0
- data/spec/cucumber/treetop_parser/feature_parser_spec.rb +98 -0
- data/spec/cucumber/treetop_parser/fit_scenario.feature +8 -0
- data/spec/cucumber/treetop_parser/given_scenario.feature +9 -0
- data/spec/cucumber/treetop_parser/multiline_steps.feature +17 -0
- data/spec/cucumber/treetop_parser/multiple_tables.feature +29 -0
- data/spec/cucumber/treetop_parser/spaces.feature +10 -0
- data/spec/cucumber/treetop_parser/test_dos.feature +25 -0
- data/spec/cucumber/treetop_parser/with_comments.feature +10 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +20 -0
- metadata +335 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
module Tree
|
|
3
|
+
class Features
|
|
4
|
+
def initialize
|
|
5
|
+
@features = []
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def length
|
|
9
|
+
@features.length
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def <<(feature)
|
|
13
|
+
@features << feature
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def accept(visitor)
|
|
17
|
+
@features.each{|feature| visitor.visit_feature(feature)}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
module Tree
|
|
3
|
+
class BaseScenario
|
|
4
|
+
attr_reader :feature
|
|
5
|
+
|
|
6
|
+
def file
|
|
7
|
+
@feature.file
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def accept(visitor)
|
|
11
|
+
steps.each do |step|
|
|
12
|
+
if step.row?
|
|
13
|
+
visitor.visit_row_step(step)
|
|
14
|
+
else
|
|
15
|
+
visitor.visit_regular_step(step)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def at_line?(l)
|
|
21
|
+
line == l || steps.map{|s| s.line}.index(l)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def previous_step(step)
|
|
25
|
+
i = steps.index(step)
|
|
26
|
+
raise "Couldn't find #{step} among #{steps}" if i.nil?
|
|
27
|
+
steps[i-1]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def pending?
|
|
31
|
+
steps.empty?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Scenario < BaseScenario
|
|
37
|
+
MIN_PADDING = 2
|
|
38
|
+
INDENT = 2
|
|
39
|
+
|
|
40
|
+
# If a table follows, the header will be stored here. Weird, but convenient.
|
|
41
|
+
attr_reader :table_header
|
|
42
|
+
attr_accessor :table_column_widths
|
|
43
|
+
attr_reader :name, :line
|
|
44
|
+
|
|
45
|
+
def initialize(feature, name, line, &proc)
|
|
46
|
+
@feature, @name, @line = feature, name, line
|
|
47
|
+
@steps_and_given_scenarios = []
|
|
48
|
+
instance_eval(&proc) if block_given?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def table_header= header
|
|
52
|
+
@table_header = header
|
|
53
|
+
update_table_column_widths header
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def steps
|
|
57
|
+
@steps ||= @steps_and_given_scenarios.map{|step| step.steps}.flatten
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def given_scenario_steps(name)
|
|
61
|
+
sibling_named(name).steps
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def sibling_named(name)
|
|
65
|
+
@feature.scenario_named(name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def length
|
|
69
|
+
@length ||= Cucumber.language['scenario'].jlength + 2 + (@name.nil? ? 0 : @name.jlength)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def max_line_length
|
|
73
|
+
[length, max_step_length].max
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def padding_length
|
|
77
|
+
padding = (max_line_length - length) + MIN_PADDING
|
|
78
|
+
padding += INDENT if length != max_line_length
|
|
79
|
+
padding
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def step_padding_length(step)
|
|
83
|
+
padding = (max_line_length - step.length) + MIN_PADDING
|
|
84
|
+
padding -= INDENT if length == max_line_length
|
|
85
|
+
padding
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def max_step_length
|
|
89
|
+
@max_step_length ||= (steps.map{|step| step.length}.max || 0)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def update_table_column_widths values
|
|
93
|
+
@table_column_widths ||= [0] * values.size
|
|
94
|
+
@table_column_widths = @table_column_widths.zip(values).map {|max, value| [max, value.size].max}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def row?
|
|
98
|
+
false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def create_step(keyword, name, line)
|
|
102
|
+
step = Step.new(self, keyword, name, line)
|
|
103
|
+
@steps_and_given_scenarios << step
|
|
104
|
+
step
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def create_given_scenario(name, line)
|
|
108
|
+
given_scenario = GivenScenario.new(self, name, line)
|
|
109
|
+
@steps_and_given_scenarios << given_scenario
|
|
110
|
+
given_scenario
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def Given(name)
|
|
114
|
+
create_step('Given', name, *caller[0].split(':')[1].to_i)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def When(name)
|
|
118
|
+
create_step('When', name, *caller[0].split(':')[1].to_i)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def Then(name)
|
|
122
|
+
create_step('Then', name, *caller[0].split(':')[1].to_i)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def And(name)
|
|
126
|
+
create_step('And', name, *caller[0].split(':')[1].to_i)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class RowScenario < BaseScenario
|
|
132
|
+
attr_reader :line
|
|
133
|
+
|
|
134
|
+
def initialize(feature, template_scenario, values, line)
|
|
135
|
+
@feature, @template_scenario, @values, @line = feature, template_scenario, values, line
|
|
136
|
+
template_scenario.update_table_column_widths values
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def row?
|
|
140
|
+
true
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def name
|
|
144
|
+
@template_scenario.name
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
#We can only cache steps once the template scenarios steps have been bound in order to know what arity the steps have
|
|
148
|
+
def steps
|
|
149
|
+
if template_steps_bound?
|
|
150
|
+
@unbound_steps = nil
|
|
151
|
+
@bound_steps ||= build_steps
|
|
152
|
+
else
|
|
153
|
+
@unbound_steps ||= build_steps
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
def build_steps
|
|
159
|
+
@template_scenario.steps.map do |template_step|
|
|
160
|
+
args = []
|
|
161
|
+
template_step.arity.times do
|
|
162
|
+
args << @values.shift
|
|
163
|
+
end
|
|
164
|
+
RowStep.new(self, template_step, args)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def template_steps_bound?
|
|
169
|
+
@template_steps_bound ||= @template_scenario.steps.inject(0) { |arity_sum, step| arity_sum + step.arity } != 0
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
module Tree
|
|
3
|
+
class BaseStep
|
|
4
|
+
attr_reader :scenario
|
|
5
|
+
attr_accessor :error
|
|
6
|
+
|
|
7
|
+
def self.new_id!
|
|
8
|
+
@next_id ||= -1
|
|
9
|
+
@next_id += 1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attr_reader :error
|
|
13
|
+
|
|
14
|
+
def file
|
|
15
|
+
@scenario.file
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def steps
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def length
|
|
23
|
+
keyword.jlength + 1 + name.jlength
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if defined?(JRUBY_VERSION)
|
|
27
|
+
PENDING_ADJUSTMENT = 2
|
|
28
|
+
REGULAR_ADJUSTMENT = 1
|
|
29
|
+
else
|
|
30
|
+
PENDING_ADJUSTMENT = 3
|
|
31
|
+
REGULAR_ADJUSTMENT = 2
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def execute_in(world, regexp, args, proc)
|
|
35
|
+
strip_pos = nil
|
|
36
|
+
begin
|
|
37
|
+
proc.call_in(world, *args)
|
|
38
|
+
rescue ArityMismatchError => e
|
|
39
|
+
e.backtrace[0] = proc.to_backtrace_line
|
|
40
|
+
strip_pos = e.backtrace.index("#{__FILE__}:#{__LINE__ - 3}:in `execute_in'")
|
|
41
|
+
format_error(strip_pos, proc, e)
|
|
42
|
+
rescue => e
|
|
43
|
+
method_line = "#{__FILE__}:#{__LINE__ - 6}:in `execute_in'"
|
|
44
|
+
method_line_pos = e.backtrace.index(method_line)
|
|
45
|
+
if method_line_pos
|
|
46
|
+
strip_pos = method_line_pos - (Pending === e ? PENDING_ADJUSTMENT : REGULAR_ADJUSTMENT)
|
|
47
|
+
else
|
|
48
|
+
# This happens with rails, because they screw up the backtrace
|
|
49
|
+
# before we get here (injecting erb stacktrace and such)
|
|
50
|
+
end
|
|
51
|
+
format_error(strip_pos, proc, e)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def format_error(strip_pos, proc, e)
|
|
56
|
+
@error = e
|
|
57
|
+
# Remove lines underneath the plain text step
|
|
58
|
+
e.backtrace[strip_pos..-1] = nil unless strip_pos.nil?
|
|
59
|
+
e.backtrace.flatten
|
|
60
|
+
# Replace the step line with something more readable
|
|
61
|
+
e.backtrace.replace(e.backtrace.map{|l| l.gsub(/`#{proc.meth}'/, "`#{keyword} #{proc.name}'")})
|
|
62
|
+
if row?
|
|
63
|
+
e.backtrace << "#{file}:#{line}:in `#{proc.name}'"
|
|
64
|
+
else
|
|
65
|
+
e.backtrace << "#{file}:#{line}:in `#{keyword} #{name}'"
|
|
66
|
+
end
|
|
67
|
+
raise e
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def id
|
|
71
|
+
@id ||= self.class.new_id!
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def actual_keyword
|
|
75
|
+
keyword == Cucumber.language['and'] ? previous_step.actual_keyword : keyword
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def previous_step
|
|
79
|
+
@scenario.previous_step(self)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def padding_length
|
|
83
|
+
@scenario.step_padding_length(self)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Step < BaseStep
|
|
88
|
+
attr_reader :keyword, :name, :line
|
|
89
|
+
attr_accessor :arity, :extra_args
|
|
90
|
+
|
|
91
|
+
def row?
|
|
92
|
+
false
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def initialize(scenario, keyword, name, line)
|
|
96
|
+
@scenario, @keyword, @name, @line = scenario, keyword, name, line
|
|
97
|
+
@extra_args = []
|
|
98
|
+
@arity = 0
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def regexp_args_proc(step_mother)
|
|
102
|
+
regexp, args, proc = step_mother.regexp_args_proc(name)
|
|
103
|
+
@arity = args.length
|
|
104
|
+
[regexp, (args + extra_args), proc]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def format(regexp, format=nil, &proc)
|
|
108
|
+
regexp.nil? ? name : name.gzub(regexp, format, &proc)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
class RowStep < BaseStep
|
|
113
|
+
attr_reader :keyword
|
|
114
|
+
|
|
115
|
+
def initialize(scenario, step, args)
|
|
116
|
+
@scenario, @step, @args = scenario, step, args
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def regexp_args_proc(step_mother)
|
|
120
|
+
regexp, _, proc = @step.regexp_args_proc(step_mother)
|
|
121
|
+
[regexp, @args, proc]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def row?
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def line
|
|
129
|
+
@scenario.line
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
module Tree
|
|
3
|
+
class Table
|
|
4
|
+
def initialize(rows)
|
|
5
|
+
@rows = rows
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def |(cell)
|
|
9
|
+
@row ||= []
|
|
10
|
+
if cell == self
|
|
11
|
+
line = *caller[0].split(':')[1].to_i
|
|
12
|
+
@row.instance_eval %{
|
|
13
|
+
def line
|
|
14
|
+
#{line}
|
|
15
|
+
end
|
|
16
|
+
}
|
|
17
|
+
@rows << @row
|
|
18
|
+
@row = nil
|
|
19
|
+
else
|
|
20
|
+
@row << cell.to_s
|
|
21
|
+
end
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
module Tree
|
|
3
|
+
class TopDownVisitor
|
|
4
|
+
def visit_features(features)
|
|
5
|
+
features.accept(self)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def visit_feature(feature)
|
|
9
|
+
feature.accept(self)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visit_header(header)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def visit_scenario(scenario)
|
|
16
|
+
scenario.accept(self)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def visit_step(step)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
%w{features feature scenario step given_scenario table top_down_visitor}.each{|f| require "cucumber/tree/#{f}"}
|
|
2
|
+
require 'cucumber/core_ext/proc'
|
|
3
|
+
require 'cucumber/core_ext/string'
|
|
4
|
+
|
|
5
|
+
module Cucumber
|
|
6
|
+
module Tree
|
|
7
|
+
def Feature(header, &proc)
|
|
8
|
+
feature = Feature.new("Feature: " + header, &proc)
|
|
9
|
+
feature.file, _, _ = *caller[0].split(':')
|
|
10
|
+
features << feature
|
|
11
|
+
feature
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def features #:nodoc:
|
|
15
|
+
@features ||= Tree::Features.new
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module Cucumber
|
|
2
|
+
# :stopdoc:
|
|
3
|
+
module TreetopParser
|
|
4
|
+
grammar Feature
|
|
5
|
+
rule root
|
|
6
|
+
space? header scenario_sequence space? {
|
|
7
|
+
def compile
|
|
8
|
+
feature = Tree::Feature.new(header.text_value.strip)
|
|
9
|
+
scenario_sequence.compile(feature)
|
|
10
|
+
feature
|
|
11
|
+
end
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
rule header
|
|
16
|
+
(!(scenario_keyword / comment_to_eol) .)+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
rule scenario_sequence
|
|
20
|
+
head:scenario? tail:(space scenario_or_table)* {
|
|
21
|
+
def compile(feature)
|
|
22
|
+
([head] + tail).each do |scenario_or_table|
|
|
23
|
+
scenario_or_table.compile(feature) if scenario_or_table.respond_to?(:compile)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def tail
|
|
28
|
+
super.elements.map { |elt| elt.scenario_or_table }
|
|
29
|
+
end
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
rule scenario
|
|
34
|
+
scenario_keyword space? name:line_to_eol steps:(space step_sequence)? {
|
|
35
|
+
def compile(feature)
|
|
36
|
+
line = input.line_of(interval.first)
|
|
37
|
+
scenario = feature.add_scenario(name.text_value.strip, line)
|
|
38
|
+
steps.step_sequence.compile(scenario) if steps.respond_to?(:step_sequence)
|
|
39
|
+
# TODO - GET RID OF THIS last_scenario NASTINESS
|
|
40
|
+
# Use a better datastructure, like a linked list...
|
|
41
|
+
Feature.last_scenario = scenario
|
|
42
|
+
end
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
rule scenario_or_table
|
|
47
|
+
scenario / more_examples
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
rule more_examples
|
|
51
|
+
more_examples_keyword table {
|
|
52
|
+
def compile(f)
|
|
53
|
+
table.compile(f)
|
|
54
|
+
end
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
rule table
|
|
59
|
+
space head:table_line body:(blank* eol space? table_line)* {
|
|
60
|
+
def compile(feature)
|
|
61
|
+
Feature.last_scenario.table_header = head.cell_values
|
|
62
|
+
body.each do |table_line|
|
|
63
|
+
feature.add_row_scenario(Feature.last_scenario, table_line.cell_values, table_line.line)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def matrix
|
|
68
|
+
([head] + body).map do |table_line|
|
|
69
|
+
table_line.cell_values # We're losing the line - we'll get it back when we make our own class
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def to_arg
|
|
74
|
+
Model::Table.new(matrix)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def body
|
|
78
|
+
super.elements.map { |elt| elt.table_line }
|
|
79
|
+
end
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
rule table_line
|
|
84
|
+
separator cells:(blank* cell_value blank* separator)+ {
|
|
85
|
+
def cell_values
|
|
86
|
+
cells.elements.map { |elt| elt.cell_value.text_value.strip }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def line
|
|
90
|
+
input.line_of(interval.first)
|
|
91
|
+
end
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
rule cell_value
|
|
96
|
+
(!(separator / eol) .)*
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
rule step_sequence
|
|
100
|
+
head:step tail:(space step)* {
|
|
101
|
+
def compile(scenario)
|
|
102
|
+
([head] + tail).each do |step|
|
|
103
|
+
step.compile(scenario)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def tail
|
|
108
|
+
super.elements.map { |elt| elt.step }
|
|
109
|
+
end
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
rule step
|
|
114
|
+
given_scenario / plain_step
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
rule given_scenario
|
|
118
|
+
given_scenario_keyword space? name:line_to_eol {
|
|
119
|
+
def compile(scenario)
|
|
120
|
+
line = input.line_of(interval.first)
|
|
121
|
+
scenario.create_given_scenario(name.text_value.strip, line)
|
|
122
|
+
end
|
|
123
|
+
}
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
rule plain_step
|
|
127
|
+
step_keyword space? name:line_to_eol multi:multiline_arg? {
|
|
128
|
+
def compile(scenario)
|
|
129
|
+
line = input.line_of(interval.first)
|
|
130
|
+
step = scenario.create_step(step_keyword.text_value, name.text_value.strip, line)
|
|
131
|
+
|
|
132
|
+
if multi.respond_to?(:to_arg)
|
|
133
|
+
step.extra_args << multi.to_arg
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
rule multiline_arg
|
|
140
|
+
table / multiline_string
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
rule multiline_string
|
|
144
|
+
eol indent:space triple_quote string:(!triple_quote .)* triple_quote {
|
|
145
|
+
def to_arg
|
|
146
|
+
indent_length = indent.text_value.length
|
|
147
|
+
significant_lines = string.text_value.split("\n")[1..-2]
|
|
148
|
+
significant_lines.map do |l|
|
|
149
|
+
l[indent_length..-1]
|
|
150
|
+
end.join("\n")
|
|
151
|
+
end
|
|
152
|
+
}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
rule triple_quote
|
|
156
|
+
'"""'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
rule separator
|
|
160
|
+
'|'
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
rule space
|
|
164
|
+
(white / comment_to_eol)+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
rule line_to_eol
|
|
168
|
+
(!eol .)*
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
rule comment_to_eol
|
|
172
|
+
'#' line_to_eol
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
rule white
|
|
176
|
+
blank / eol
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
rule blank
|
|
180
|
+
[ \t]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
rule eol
|
|
184
|
+
("\r" "\n"?) / "\n"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
rule step_keyword
|
|
188
|
+
"<%= words['given'] %>" / "<%= words['when'] %>" / "<%= words['then'] %>" / "<%= words['and'] %>" / "<%= words['but'] %>"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
rule scenario_keyword
|
|
192
|
+
"<%= words['scenario'] %>" ":"?
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
rule more_examples_keyword
|
|
196
|
+
"<%= words['more_examples'] %>" ":"?
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
rule given_scenario_keyword
|
|
200
|
+
"<%= words['given_scenario'] %>" ":"?
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
end
|