cuke_modeler 1.3.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +60 -17
- data/CHANGELOG.md +312 -0
- data/Gemfile +19 -3
- data/LICENSE.txt +1 -1
- data/README.md +17 -7
- data/Rakefile +45 -28
- data/appveyor.yml +57 -17
- data/cuke_modeler.gemspec +6 -3
- data/lib/cuke_modeler/adapters/gherkin_2_adapter.rb +1 -0
- data/lib/cuke_modeler/adapters/gherkin_3_adapter.rb +1 -0
- data/lib/cuke_modeler/adapters/gherkin_4_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_5_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_6_adapter.rb +310 -0
- data/lib/cuke_modeler/adapters/gherkin_7_adapter.rb +307 -0
- data/lib/cuke_modeler/adapters/gherkin_8_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_9_adapter.rb +12 -0
- data/lib/cuke_modeler/containing.rb +16 -0
- data/lib/cuke_modeler/described.rb +1 -0
- data/lib/cuke_modeler/models/step.rb +31 -2
- data/lib/cuke_modeler/named.rb +1 -0
- data/lib/cuke_modeler/nested.rb +1 -0
- data/lib/cuke_modeler/parsed.rb +1 -0
- data/lib/cuke_modeler/parsing.rb +116 -68
- data/lib/cuke_modeler/sourceable.rb +1 -0
- data/lib/cuke_modeler/stepped.rb +1 -0
- data/lib/cuke_modeler/taggable.rb +1 -0
- data/lib/cuke_modeler/version.rb +1 -1
- data/testing/cucumber/features/analysis/step_comparison.feature +25 -0
- data/testing/cucumber/features/analysis/test_comparison.feature +1 -1
- data/testing/cucumber/step_definitions/feature_file_steps.rb +1 -1
- data/testing/cucumber/step_definitions/modeling_steps.rb +7 -2
- data/testing/cucumber/step_definitions/verification_steps.rb +11 -2
- data/testing/file_helper.rb +3 -0
- data/testing/gemfiles/gherkin2.gemfile +8 -0
- data/testing/gemfiles/gherkin3.gemfile +6 -0
- data/testing/gemfiles/gherkin4.gemfile +7 -0
- data/testing/gemfiles/gherkin5.gemfile +7 -0
- data/testing/gemfiles/gherkin6.gemfile +10 -0
- data/testing/gemfiles/gherkin7.gemfile +9 -0
- data/testing/gemfiles/gherkin8.gemfile +9 -0
- data/testing/gemfiles/gherkin9.gemfile +9 -0
- data/testing/helper_methods.rb +23 -0
- data/testing/rspec/spec/integration/{gherkin_2_adapter_spec.rb → adapters/gherkin_2_adapter_spec.rb} +13 -13
- data/testing/rspec/spec/integration/{gherkin_3_adapter_spec.rb → adapters/gherkin_3_adapter_spec.rb} +13 -13
- data/testing/rspec/spec/integration/{gherkin_4_adapter_spec.rb → adapters/gherkin_4_adapter_spec.rb} +13 -13
- data/testing/rspec/spec/integration/adapters/gherkin_5_adapter_spec.rb +165 -0
- data/testing/rspec/spec/integration/adapters/gherkin_6_adapter_spec.rb +159 -0
- data/testing/rspec/spec/integration/adapters/gherkin_7_adapter_spec.rb +162 -0
- data/testing/rspec/spec/integration/adapters/gherkin_8_adapter_spec.rb +162 -0
- data/testing/rspec/spec/integration/adapters/gherkin_9_adapter_spec.rb +162 -0
- data/testing/rspec/spec/integration/{background_integration_spec.rb → models/background_integration_spec.rb} +90 -86
- data/testing/rspec/spec/integration/{cell_integration_spec.rb → models/cell_integration_spec.rb} +49 -38
- data/testing/rspec/spec/integration/{comment_integration_spec.rb → models/comment_integration_spec.rb} +31 -20
- data/testing/rspec/spec/integration/{directory_integration_spec.rb → models/directory_integration_spec.rb} +3 -3
- data/testing/rspec/spec/integration/{doc_string_integration_spec.rb → models/doc_string_integration_spec.rb} +39 -35
- data/testing/rspec/spec/integration/{example_integration_spec.rb → models/example_integration_spec.rb} +109 -83
- data/testing/rspec/spec/integration/{feature_file_integration_spec.rb → models/feature_file_integration_spec.rb} +52 -38
- data/testing/rspec/spec/integration/{feature_integration_spec.rb → models/feature_integration_spec.rb} +125 -112
- data/testing/rspec/spec/integration/{model_integration_spec.rb → models/model_integration_spec.rb} +1 -1
- data/testing/rspec/spec/integration/{outline_integration_spec.rb → models/outline_integration_spec.rb} +138 -129
- data/testing/rspec/spec/integration/{row_integration_spec.rb → models/row_integration_spec.rb} +55 -35
- data/testing/rspec/spec/integration/{scenario_integration_spec.rb → models/scenario_integration_spec.rb} +92 -88
- data/testing/rspec/spec/integration/models/step_integration_spec.rb +573 -0
- data/testing/rspec/spec/integration/{table_integration_spec.rb → models/table_integration_spec.rb} +38 -34
- data/testing/rspec/spec/integration/{tag_integration_spec.rb → models/tag_integration_spec.rb} +56 -36
- data/testing/rspec/spec/integration/parsing_integration_spec.rb +45 -7
- data/testing/rspec/spec/spec_helper.rb +79 -43
- data/testing/rspec/spec/unit/cuke_modeler_unit_spec.rb +25 -0
- data/testing/rspec/spec/unit/{background_unit_spec.rb → models/background_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{cell_unit_spec.rb → models/cell_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{comment_unit_spec.rb → models/comment_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{directory_unit_spec.rb → models/directory_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{doc_string_unit_spec.rb → models/doc_string_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{example_unit_spec.rb → models/example_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{feature_file_unit_spec.rb → models/feature_file_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{feature_unit_spec.rb → models/feature_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{model_unit_spec.rb → models/model_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{outline_unit_spec.rb → models/outline_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{row_unit_spec.rb → models/row_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{scenario_unit_spec.rb → models/scenario_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{step_unit_spec.rb → models/step_unit_spec.rb} +2 -2
- data/testing/rspec/spec/unit/{table_unit_spec.rb → models/table_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/{tag_unit_spec.rb → models/tag_unit_spec.rb} +1 -1
- data/testing/rspec/spec/unit/shared/containing_models_unit_specs.rb +102 -0
- data/todo.txt +5 -2
- metadata +80 -47
- data/History.md +0 -186
- data/testing/cucumber/support/transforms.rb +0 -3
- data/testing/rspec/spec/integration/step_integration_spec.rb +0 -459
@@ -0,0 +1,307 @@
|
|
1
|
+
module CukeModeler
|
2
|
+
|
3
|
+
# NOT A PART OF THE PUBLIC API
|
4
|
+
# An adapter that can convert the output of version 7.x of the *gherkin* gem into input that is consumable by this gem.
|
5
|
+
|
6
|
+
class Gherkin7Adapter
|
7
|
+
|
8
|
+
# Adapts the given AST into the shape that this gem expects
|
9
|
+
def adapt(parsed_ast)
|
10
|
+
# Saving off the original data
|
11
|
+
parsed_ast['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_ast))
|
12
|
+
|
13
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
14
|
+
parsed_ast['cuke_modeler_parsing_data'][:feature] = nil
|
15
|
+
parsed_ast['cuke_modeler_parsing_data'][:comments] = nil
|
16
|
+
|
17
|
+
parsed_ast['comments'] = []
|
18
|
+
parsed_ast[:comments].each do |comment|
|
19
|
+
adapt_comment!(comment)
|
20
|
+
end
|
21
|
+
parsed_ast['comments'].concat(parsed_ast.delete(:comments))
|
22
|
+
|
23
|
+
adapt_feature!(parsed_ast[:feature]) if parsed_ast[:feature]
|
24
|
+
parsed_ast['feature'] = parsed_ast.delete(:feature)
|
25
|
+
|
26
|
+
[parsed_ast]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Adapts the AST sub-tree that is rooted at the given feature node.
|
30
|
+
def adapt_feature!(parsed_feature)
|
31
|
+
# Saving off the original data
|
32
|
+
parsed_feature['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_feature))
|
33
|
+
|
34
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
35
|
+
parsed_feature['cuke_modeler_parsing_data'][:tags] = nil
|
36
|
+
parsed_feature['cuke_modeler_parsing_data'][:children] = nil
|
37
|
+
|
38
|
+
parsed_feature['keyword'] = parsed_feature.delete(:keyword)
|
39
|
+
parsed_feature['name'] = parsed_feature.delete(:name)
|
40
|
+
parsed_feature['description'] = parsed_feature.delete(:description)
|
41
|
+
parsed_feature['line'] = parsed_feature.delete(:location)[:line]
|
42
|
+
|
43
|
+
parsed_feature['elements'] = []
|
44
|
+
adapt_child_elements!(parsed_feature[:children])
|
45
|
+
parsed_feature['elements'].concat(parsed_feature.delete(:children))
|
46
|
+
|
47
|
+
parsed_feature['tags'] = []
|
48
|
+
parsed_feature[:tags].each do |tag|
|
49
|
+
adapt_tag!(tag)
|
50
|
+
end
|
51
|
+
parsed_feature['tags'].concat(parsed_feature.delete(:tags))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Adapts the AST sub-tree that is rooted at the given background node.
|
55
|
+
def adapt_background!(parsed_background)
|
56
|
+
# Saving off the original data
|
57
|
+
parsed_background['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_background))
|
58
|
+
|
59
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
60
|
+
parsed_background['cuke_modeler_parsing_data'][:background][:steps] = nil
|
61
|
+
|
62
|
+
parsed_background['type'] = 'Background'
|
63
|
+
parsed_background['keyword'] = parsed_background[:background].delete(:keyword)
|
64
|
+
parsed_background['name'] = parsed_background[:background].delete(:name)
|
65
|
+
parsed_background['description'] = parsed_background[:background].delete(:description)
|
66
|
+
parsed_background['line'] = parsed_background[:background].delete(:location)[:line]
|
67
|
+
|
68
|
+
parsed_background['steps'] = []
|
69
|
+
parsed_background[:background][:steps].each do |step|
|
70
|
+
adapt_step!(step)
|
71
|
+
end
|
72
|
+
parsed_background['steps'].concat(parsed_background[:background].delete(:steps))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Adapts the AST sub-tree that is rooted at the given scenario node.
|
76
|
+
def adapt_scenario!(parsed_test)
|
77
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
78
|
+
parsed_test['cuke_modeler_parsing_data'][:scenario][:tags] = nil
|
79
|
+
parsed_test['cuke_modeler_parsing_data'][:scenario][:steps] = nil
|
80
|
+
|
81
|
+
parsed_test['type'] = 'Scenario'
|
82
|
+
parsed_test['keyword'] = parsed_test[:scenario].delete(:keyword)
|
83
|
+
parsed_test['name'] = parsed_test[:scenario].delete(:name)
|
84
|
+
parsed_test['description'] = parsed_test[:scenario].delete(:description)
|
85
|
+
parsed_test['line'] = parsed_test[:scenario].delete(:location)[:line]
|
86
|
+
|
87
|
+
parsed_test['tags'] = []
|
88
|
+
parsed_test[:scenario][:tags].each do |tag|
|
89
|
+
adapt_tag!(tag)
|
90
|
+
end
|
91
|
+
parsed_test['tags'].concat(parsed_test[:scenario].delete(:tags))
|
92
|
+
|
93
|
+
parsed_test['steps'] = []
|
94
|
+
parsed_test[:scenario][:steps].each do |step|
|
95
|
+
adapt_step!(step)
|
96
|
+
end
|
97
|
+
parsed_test['steps'].concat(parsed_test[:scenario].delete(:steps))
|
98
|
+
end
|
99
|
+
|
100
|
+
# Adapts the AST sub-tree that is rooted at the given outline node.
|
101
|
+
def adapt_outline!(parsed_test)
|
102
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
103
|
+
parsed_test['cuke_modeler_parsing_data'][:scenario][:tags] = nil
|
104
|
+
parsed_test['cuke_modeler_parsing_data'][:scenario][:steps] = nil
|
105
|
+
parsed_test['cuke_modeler_parsing_data'][:scenario][:examples] = nil
|
106
|
+
|
107
|
+
parsed_test['type'] = 'ScenarioOutline'
|
108
|
+
parsed_test['keyword'] = parsed_test[:scenario].delete(:keyword)
|
109
|
+
parsed_test['name'] = parsed_test[:scenario].delete(:name)
|
110
|
+
parsed_test['description'] = parsed_test[:scenario].delete(:description)
|
111
|
+
parsed_test['line'] = parsed_test[:scenario].delete(:location)[:line]
|
112
|
+
|
113
|
+
parsed_test['tags'] = []
|
114
|
+
parsed_test[:scenario][:tags].each do |tag|
|
115
|
+
adapt_tag!(tag)
|
116
|
+
end
|
117
|
+
parsed_test['tags'].concat(parsed_test[:scenario].delete(:tags))
|
118
|
+
|
119
|
+
parsed_test['steps'] = []
|
120
|
+
parsed_test[:scenario][:steps].each do |step|
|
121
|
+
adapt_step!(step)
|
122
|
+
end
|
123
|
+
parsed_test['steps'].concat(parsed_test[:scenario].delete(:steps))
|
124
|
+
|
125
|
+
parsed_test['examples'] = []
|
126
|
+
parsed_test[:scenario][:examples].each do |step|
|
127
|
+
adapt_example!(step)
|
128
|
+
end
|
129
|
+
parsed_test['examples'].concat(parsed_test[:scenario].delete(:examples))
|
130
|
+
end
|
131
|
+
|
132
|
+
# Adapts the AST sub-tree that is rooted at the given example node.
|
133
|
+
def adapt_example!(parsed_example)
|
134
|
+
# Saving off the original data
|
135
|
+
parsed_example['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_example))
|
136
|
+
|
137
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
138
|
+
parsed_example['cuke_modeler_parsing_data'][:tags] = nil
|
139
|
+
parsed_example['cuke_modeler_parsing_data'][:table_header] = nil
|
140
|
+
parsed_example['cuke_modeler_parsing_data'][:table_body] = nil
|
141
|
+
|
142
|
+
parsed_example['keyword'] = parsed_example.delete(:keyword)
|
143
|
+
parsed_example['name'] = parsed_example.delete(:name)
|
144
|
+
parsed_example['line'] = parsed_example.delete(:location)[:line]
|
145
|
+
parsed_example['description'] = parsed_example.delete(:description)
|
146
|
+
|
147
|
+
parsed_example['rows'] = []
|
148
|
+
|
149
|
+
if parsed_example[:table_header]
|
150
|
+
adapt_table_row!(parsed_example[:table_header])
|
151
|
+
parsed_example['rows'] << parsed_example.delete(:table_header)
|
152
|
+
end
|
153
|
+
|
154
|
+
if parsed_example[:table_body]
|
155
|
+
parsed_example[:table_body].each do |row|
|
156
|
+
adapt_table_row!(row)
|
157
|
+
end
|
158
|
+
parsed_example['rows'].concat(parsed_example.delete(:table_body))
|
159
|
+
end
|
160
|
+
|
161
|
+
parsed_example['tags'] = []
|
162
|
+
parsed_example[:tags].each do |tag|
|
163
|
+
adapt_tag!(tag)
|
164
|
+
end
|
165
|
+
parsed_example['tags'].concat(parsed_example.delete(:tags))
|
166
|
+
end
|
167
|
+
|
168
|
+
# Adapts the AST sub-tree that is rooted at the given tag node.
|
169
|
+
def adapt_tag!(parsed_tag)
|
170
|
+
# Saving off the original data
|
171
|
+
parsed_tag['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_tag))
|
172
|
+
|
173
|
+
parsed_tag['name'] = parsed_tag.delete(:name)
|
174
|
+
parsed_tag['line'] = parsed_tag.delete(:location)[:line]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Adapts the AST sub-tree that is rooted at the given comment node.
|
178
|
+
def adapt_comment!(parsed_comment)
|
179
|
+
# Saving off the original data
|
180
|
+
parsed_comment['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_comment))
|
181
|
+
|
182
|
+
parsed_comment['text'] = parsed_comment.delete(:text)
|
183
|
+
parsed_comment['line'] = parsed_comment.delete(:location)[:line]
|
184
|
+
end
|
185
|
+
|
186
|
+
# Adapts the AST sub-tree that is rooted at the given step node.
|
187
|
+
def adapt_step!(parsed_step)
|
188
|
+
# Saving off the original data
|
189
|
+
parsed_step['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_step))
|
190
|
+
|
191
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
192
|
+
parsed_step['cuke_modeler_parsing_data'][:data_table] = nil
|
193
|
+
parsed_step['cuke_modeler_parsing_data'][:doc_string] = nil
|
194
|
+
|
195
|
+
parsed_step['keyword'] = parsed_step.delete(:keyword)
|
196
|
+
parsed_step['name'] = parsed_step.delete(:text)
|
197
|
+
parsed_step['line'] = parsed_step.delete(:location)[:line]
|
198
|
+
|
199
|
+
|
200
|
+
case
|
201
|
+
when parsed_step[:doc_string]
|
202
|
+
adapt_doc_string!(parsed_step[:doc_string])
|
203
|
+
parsed_step['doc_string'] = parsed_step.delete(:doc_string)
|
204
|
+
when parsed_step[:data_table]
|
205
|
+
adapt_step_table!(parsed_step[:data_table])
|
206
|
+
parsed_step['table'] = parsed_step.delete(:data_table)
|
207
|
+
else
|
208
|
+
# Step has no extra argument
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Adapts the AST sub-tree that is rooted at the given doc string node.
|
213
|
+
def adapt_doc_string!(parsed_doc_string)
|
214
|
+
# Saving off the original data
|
215
|
+
parsed_doc_string['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_doc_string))
|
216
|
+
|
217
|
+
parsed_doc_string['value'] = parsed_doc_string.delete(:content)
|
218
|
+
parsed_doc_string['content_type'] = parsed_doc_string.delete(:content_type).strip # TODO: fix bug in Gherkin so that this whitespace is already trimmed off
|
219
|
+
parsed_doc_string['line'] = parsed_doc_string.delete(:location)[:line]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Adapts the AST sub-tree that is rooted at the given table node.
|
223
|
+
def adapt_step_table!(parsed_step_table)
|
224
|
+
# Saving off the original data
|
225
|
+
parsed_step_table['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_step_table))
|
226
|
+
|
227
|
+
# Removing parsed data for child elements in order to avoid duplicating data
|
228
|
+
parsed_step_table['cuke_modeler_parsing_data'][:rows] = nil
|
229
|
+
|
230
|
+
parsed_step_table['rows'] = []
|
231
|
+
parsed_step_table[:rows].each do |row|
|
232
|
+
adapt_table_row!(row)
|
233
|
+
end
|
234
|
+
parsed_step_table['rows'].concat(parsed_step_table.delete(:rows))
|
235
|
+
parsed_step_table['line'] = parsed_step_table.delete(:location)[:line]
|
236
|
+
end
|
237
|
+
|
238
|
+
# Adapts the AST sub-tree that is rooted at the given row node.
|
239
|
+
def adapt_table_row!(parsed_table_row)
|
240
|
+
# Saving off the original data
|
241
|
+
parsed_table_row['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_table_row))
|
242
|
+
|
243
|
+
# Removing parsed data for child elements in order to avoid duplicating data which the child elements will themselves include
|
244
|
+
parsed_table_row['cuke_modeler_parsing_data'][:cells] = nil
|
245
|
+
|
246
|
+
|
247
|
+
parsed_table_row['line'] = parsed_table_row.delete(:location)[:line]
|
248
|
+
|
249
|
+
parsed_table_row['cells'] = []
|
250
|
+
parsed_table_row[:cells].each do |row|
|
251
|
+
adapt_table_cell!(row)
|
252
|
+
end
|
253
|
+
parsed_table_row['cells'].concat(parsed_table_row.delete(:cells))
|
254
|
+
end
|
255
|
+
|
256
|
+
# Adapts the AST sub-tree that is rooted at the given cell node.
|
257
|
+
def adapt_table_cell!(parsed_cell)
|
258
|
+
# Saving off the original data
|
259
|
+
parsed_cell['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_cell))
|
260
|
+
|
261
|
+
parsed_cell['value'] = parsed_cell.delete(:value)
|
262
|
+
parsed_cell['line'] = parsed_cell.delete(:location)[:line]
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
private
|
267
|
+
|
268
|
+
|
269
|
+
def adapt_child_elements!(parsed_children)
|
270
|
+
return if parsed_children.empty?
|
271
|
+
|
272
|
+
background_child = parsed_children.find { |child| child[:background] }
|
273
|
+
|
274
|
+
if background_child
|
275
|
+
adapt_background!(background_child)
|
276
|
+
|
277
|
+
remaining_children = parsed_children.reject { |child| child[:background] }
|
278
|
+
end
|
279
|
+
|
280
|
+
adapt_tests!(remaining_children || parsed_children)
|
281
|
+
end
|
282
|
+
|
283
|
+
def adapt_tests!(parsed_tests)
|
284
|
+
return unless parsed_tests
|
285
|
+
|
286
|
+
parsed_tests.each do |test|
|
287
|
+
adapt_test!(test)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def adapt_test!(parsed_test)
|
292
|
+
# Saving off the original data
|
293
|
+
parsed_test['cuke_modeler_parsing_data'] = Marshal::load(Marshal.dump(parsed_test))
|
294
|
+
|
295
|
+
|
296
|
+
case
|
297
|
+
when parsed_test[:scenario] && parsed_test[:scenario][:examples].any?
|
298
|
+
adapt_outline!(parsed_test)
|
299
|
+
when parsed_test[:scenario]
|
300
|
+
adapt_scenario!(parsed_test)
|
301
|
+
else
|
302
|
+
raise(ArgumentError, "Unknown test type with keys: #{parsed_test.keys}")
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'gherkin_7_adapter'
|
2
|
+
|
3
|
+
module CukeModeler
|
4
|
+
|
5
|
+
# NOT A PART OF THE PUBLIC API
|
6
|
+
# An adapter that can convert the output of version 8.x of the *gherkin* gem into input that is consumable by this gem.
|
7
|
+
|
8
|
+
class Gherkin8Adapter < Gherkin7Adapter
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'gherkin_7_adapter'
|
2
|
+
|
3
|
+
module CukeModeler
|
4
|
+
|
5
|
+
# NOT A PART OF THE PUBLIC API
|
6
|
+
# An adapter that can convert the output of version 9.x of the *gherkin* gem into input that is consumable by this gem.
|
7
|
+
|
8
|
+
class Gherkin9Adapter < Gherkin7Adapter
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -1,9 +1,25 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
|
+
# NOT A PART OF THE PUBLIC API
|
3
4
|
# A mix-in module containing methods used by models that contain other models.
|
4
5
|
|
5
6
|
module Containing
|
6
7
|
|
8
|
+
# Executes the given code block with every model that is a child of this model.
|
9
|
+
def each_descendant(&block)
|
10
|
+
children.each do |child_model|
|
11
|
+
block.call(child_model)
|
12
|
+
child_model.each_descendant(&block) if child_model.respond_to?(:each_descendant)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the given code block with this model and every model that is a child of this model.
|
17
|
+
def each_model(&block)
|
18
|
+
block.call(self)
|
19
|
+
|
20
|
+
each_descendant(&block)
|
21
|
+
end
|
22
|
+
|
7
23
|
|
8
24
|
private
|
9
25
|
|
@@ -33,9 +33,11 @@ module CukeModeler
|
|
33
33
|
# Returns *true* if the two steps have the same base text (i.e. minus any keyword,
|
34
34
|
# table, or doc string and *false* otherwise.
|
35
35
|
def ==(other_step)
|
36
|
-
return false unless other_step.
|
36
|
+
return false unless other_step.is_a?(CukeModeler::Step)
|
37
37
|
|
38
|
-
|
38
|
+
text_matches?(other_step) &&
|
39
|
+
table_matches?(other_step) &&
|
40
|
+
doc_string_matches?(other_step)
|
39
41
|
end
|
40
42
|
|
41
43
|
# Returns the model objects that belong to this model.
|
@@ -65,5 +67,32 @@ module CukeModeler
|
|
65
67
|
parsed_file.first['feature']['elements'].first['steps'].first
|
66
68
|
end
|
67
69
|
|
70
|
+
def text_matches?(other_step)
|
71
|
+
text == other_step.text
|
72
|
+
end
|
73
|
+
|
74
|
+
def table_matches?(other_step)
|
75
|
+
return false if (!block.is_a?(CukeModeler::Table) || !other_step.block.is_a?(CukeModeler::Table)) && (block.is_a?(CukeModeler::Table) || other_step.block.is_a?(CukeModeler::Table))
|
76
|
+
return true unless block.is_a?(CukeModeler::Table) && other_step.block.is_a?(CukeModeler::Table)
|
77
|
+
|
78
|
+
first_step_values = block.rows.collect { |table_row| table_row.cells.map(&:value) }
|
79
|
+
second_step_values = other_step.block.rows.collect { |table_row| table_row.cells.map(&:value) }
|
80
|
+
|
81
|
+
first_step_values == second_step_values
|
82
|
+
end
|
83
|
+
|
84
|
+
def doc_string_matches?(other_step)
|
85
|
+
return false if (!block.is_a?(CukeModeler::DocString) || !other_step.block.is_a?(CukeModeler::DocString)) && (block.is_a?(CukeModeler::DocString) || other_step.block.is_a?(CukeModeler::DocString))
|
86
|
+
return true unless block.is_a?(CukeModeler::DocString) && other_step.block.is_a?(CukeModeler::DocString)
|
87
|
+
|
88
|
+
first_content = block.content
|
89
|
+
first_content_type = block.content_type
|
90
|
+
second_content = other_step.block.content
|
91
|
+
second_content_type = other_step.block.content_type
|
92
|
+
|
93
|
+
(first_content == second_content) &&
|
94
|
+
(first_content_type == second_content_type)
|
95
|
+
end
|
96
|
+
|
68
97
|
end
|
69
98
|
end
|
data/lib/cuke_modeler/named.rb
CHANGED
data/lib/cuke_modeler/nested.rb
CHANGED
data/lib/cuke_modeler/parsed.rb
CHANGED
data/lib/cuke_modeler/parsing.rb
CHANGED
@@ -1,75 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
# The *gherkin* gem loads differently and has different grammar rules across major versions. Parsing
|
19
|
-
# will be done with an 'adapter' appropriate to the version of the *gherkin* gem that has been activated.
|
20
|
-
|
21
|
-
case Gem.loaded_specs['gherkin'].version.version
|
22
|
-
when /^[54]\./
|
23
|
-
require 'gherkin/parser'
|
24
|
-
require 'cuke_modeler/adapters/gherkin_4_adapter'
|
25
|
-
|
26
|
-
|
27
|
-
# todo - make these methods private?
|
28
|
-
def self.parsing_method(source_text, _filename)
|
29
|
-
Gherkin::Parser.new.parse(source_text)
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.adapter_class
|
33
|
-
CukeModeler::Gherkin4Adapter
|
34
|
-
end
|
35
|
-
|
36
|
-
when /^3\./
|
37
|
-
require 'gherkin/parser'
|
38
|
-
require 'cuke_modeler/adapters/gherkin_3_adapter'
|
1
|
+
# Have to at least load some version of the gem before which version of the gem has been loaded can
|
2
|
+
# be determined and the rest of the needed files can be loaded. The entry points vary across versions,
|
3
|
+
# so try them all until one of them works.
|
4
|
+
begin
|
5
|
+
# Gherkin 2.x, 8.x, 9.x
|
6
|
+
require 'gherkin'
|
7
|
+
rescue LoadError
|
8
|
+
begin
|
9
|
+
require 'gherkin/parser'
|
10
|
+
rescue LoadError
|
11
|
+
# Gherkin 6.x, 7.x
|
12
|
+
require 'gherkin/gherkin'
|
13
|
+
end
|
14
|
+
end
|
39
15
|
|
40
16
|
|
41
|
-
|
42
|
-
|
43
|
-
|
17
|
+
# The *gherkin* gem loads differently and has different grammar rules across major versions. Parsing
|
18
|
+
# will be done with an 'adapter' appropriate to the version of the *gherkin* gem that has been activated.
|
19
|
+
|
20
|
+
gherkin_version = Gem.loaded_specs['gherkin'].version.version
|
21
|
+
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
22
|
+
|
23
|
+
case gherkin_major_version
|
24
|
+
when 6, 7, 8, 9
|
25
|
+
require 'gherkin/dialect'
|
26
|
+
when 3, 4, 5
|
27
|
+
require 'gherkin/parser'
|
28
|
+
when 2
|
29
|
+
require 'stringio'
|
30
|
+
require 'gherkin/formatter/json_formatter'
|
31
|
+
require 'gherkin'
|
32
|
+
require 'json'
|
33
|
+
require 'multi_json'
|
34
|
+
else
|
35
|
+
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
36
|
+
end
|
44
37
|
|
45
|
-
|
46
|
-
CukeModeler::Gherkin3Adapter
|
47
|
-
end
|
38
|
+
require "cuke_modeler/adapters/gherkin_#{gherkin_major_version}_adapter"
|
48
39
|
|
49
|
-
else # Assume version 2.x
|
50
|
-
require 'stringio'
|
51
|
-
require 'gherkin/formatter/json_formatter'
|
52
|
-
require 'gherkin'
|
53
|
-
require 'json'
|
54
|
-
require 'multi_json'
|
55
|
-
require 'cuke_modeler/adapters/gherkin_2_adapter'
|
56
|
-
|
57
|
-
|
58
|
-
def self.parsing_method(source_text, filename)
|
59
|
-
io = StringIO.new
|
60
|
-
formatter = Gherkin::Formatter::JSONFormatter.new(io)
|
61
|
-
parser = Gherkin::Parser::Parser.new(formatter)
|
62
|
-
parser.parse(source_text, filename, 0)
|
63
|
-
formatter.done
|
64
|
-
MultiJson.load(io.string)
|
65
|
-
end
|
66
40
|
|
67
|
-
|
68
|
-
CukeModeler::Gherkin2Adapter
|
69
|
-
end
|
41
|
+
module CukeModeler
|
70
42
|
|
71
|
-
|
43
|
+
# A module providing source text parsing functionality.
|
72
44
|
|
45
|
+
module Parsing
|
73
46
|
|
74
47
|
class << self
|
75
48
|
|
@@ -96,17 +69,92 @@ module CukeModeler
|
|
96
69
|
def parse_text(source_text, filename = 'cuke_modeler_fake_file.feature')
|
97
70
|
raise(ArgumentError, "Text to parse must be a String but got #{source_text.class}") unless source_text.is_a?(String)
|
98
71
|
|
99
|
-
|
100
72
|
begin
|
101
73
|
parsed_result = parsing_method(source_text, filename)
|
102
74
|
rescue => e
|
103
75
|
raise(ArgumentError, "Error encountered while parsing '#{filename}'\n#{e.class} - #{e.message}")
|
104
76
|
end
|
105
77
|
|
106
|
-
|
78
|
+
adapter_class.new.adapt(parsed_result)
|
79
|
+
end
|
80
|
+
|
107
81
|
|
82
|
+
gherkin_version = Gem.loaded_specs['gherkin'].version.version
|
83
|
+
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
84
|
+
|
85
|
+
case gherkin_major_version
|
86
|
+
when 9
|
87
|
+
# NOT A PART OF THE PUBLIC API
|
88
|
+
# The method to use for parsing Gherkin text
|
89
|
+
def parsing_method(source_text, filename)
|
90
|
+
messages = Gherkin.from_source(filename, source_text, { :include_gherkin_document => true }).to_a.map(&:to_hash)
|
91
|
+
|
92
|
+
potential_error_message = messages.find { |message| message[:attachment] }
|
93
|
+
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
94
|
+
|
95
|
+
if potential_error_message
|
96
|
+
raise potential_error_message[:attachment][:data] if potential_error_message[:attachment][:data] =~ /expected.*got/
|
97
|
+
end
|
98
|
+
|
99
|
+
gherkin_ast_message[:gherkin_document]
|
100
|
+
end
|
101
|
+
when 8
|
102
|
+
# NOT A PART OF THE PUBLIC API
|
103
|
+
# The method to use for parsing Gherkin text
|
104
|
+
def parsing_method(source_text, filename)
|
105
|
+
messages = Gherkin.from_source(filename, source_text, { :include_gherkin_document => true }).to_a.map(&:to_hash)
|
106
|
+
|
107
|
+
potential_error_message = messages.find { |message| message[:attachment] }
|
108
|
+
gherkin_ast_message = messages.find { |message| message[:gherkinDocument] }
|
109
|
+
|
110
|
+
if potential_error_message
|
111
|
+
raise potential_error_message[:attachment][:data] if potential_error_message[:attachment][:data] =~ /expected.*got/
|
112
|
+
end
|
113
|
+
|
114
|
+
gherkin_ast_message[:gherkinDocument]
|
115
|
+
end
|
116
|
+
when 6, 7
|
117
|
+
# NOT A PART OF THE PUBLIC API
|
118
|
+
# The method to use for parsing Gherkin text
|
119
|
+
def parsing_method(source_text, filename)
|
120
|
+
messages = Gherkin::Gherkin.from_source(filename, source_text).to_a.map(&:to_hash)
|
121
|
+
|
122
|
+
potential_error_message = messages.find { |message| message[:attachment] }
|
123
|
+
gherkin_ast_message = messages.find { |message| message[:gherkinDocument] }
|
124
|
+
|
125
|
+
if potential_error_message
|
126
|
+
raise potential_error_message[:attachment][:data] if potential_error_message[:attachment][:data] =~ /expected.*got/
|
127
|
+
end
|
128
|
+
|
129
|
+
gherkin_ast_message[:gherkinDocument]
|
130
|
+
end
|
131
|
+
when 3, 4, 5
|
132
|
+
# todo - make these methods private?
|
133
|
+
# NOT A PART OF THE PUBLIC API
|
134
|
+
# The method to use for parsing Gherkin text
|
135
|
+
# Filename isn't used by this version of Gherkin but keeping the parameter so that the calling method only has to know one method signature
|
136
|
+
def parsing_method(source_text, _filename)
|
137
|
+
Gherkin::Parser.new.parse(source_text)
|
138
|
+
end
|
139
|
+
when 2
|
140
|
+
# NOT A PART OF THE PUBLIC API
|
141
|
+
# The method to use for parsing Gherkin text
|
142
|
+
def parsing_method(source_text, filename)
|
143
|
+
io = StringIO.new
|
144
|
+
formatter = Gherkin::Formatter::JSONFormatter.new(io)
|
145
|
+
parser = Gherkin::Parser::Parser.new(formatter)
|
146
|
+
parser.parse(source_text, filename, 0)
|
147
|
+
formatter.done
|
148
|
+
MultiJson.load(io.string)
|
149
|
+
end
|
150
|
+
else
|
151
|
+
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
152
|
+
end
|
108
153
|
|
109
|
-
|
154
|
+
# NOT A PART OF THE PUBLIC API
|
155
|
+
# The adapter to use when converting an AST to a standard internal shape
|
156
|
+
define_method('adapter_class') do
|
157
|
+
CukeModeler.const_get("Gherkin#{gherkin_major_version}Adapter")
|
110
158
|
end
|
111
159
|
|
112
160
|
end
|