macros4cuke 0.3.42 → 0.4.00

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 (35) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +20 -3
  3. data/CHANGELOG.md +15 -1
  4. data/examples/i18n/fr/features/step_definitions/use_macro_steps.rb +1 -1
  5. data/features/demo06.feature +75 -75
  6. data/features/demo07.feature +15 -0
  7. data/features/support/env.rb +6 -0
  8. data/features/support/macro_support.rb +2 -2
  9. data/lib/macro_steps.rb +19 -2
  10. data/lib/macros4cuke/coll-walker-factory.rb +119 -0
  11. data/lib/macros4cuke/constants.rb +1 -1
  12. data/lib/macros4cuke/exceptions.rb +23 -1
  13. data/lib/macros4cuke/formatter/all-notifications.rb +30 -0
  14. data/lib/macros4cuke/formatter/to-gherkin.rb +80 -0
  15. data/lib/macros4cuke/formatter/to-null.rb +86 -0
  16. data/lib/macros4cuke/formatter/to-trace.rb +100 -0
  17. data/lib/macros4cuke/formatting-service.rb +74 -0
  18. data/lib/macros4cuke/macro-collection.rb +3 -3
  19. data/lib/macros4cuke/macro-step-support.rb +1 -1
  20. data/lib/macros4cuke/macro-step.rb +10 -26
  21. data/lib/macros4cuke/templating/engine.rb +74 -29
  22. data/spec/macros4cuke/coll-walker-factory_spec.rb +269 -0
  23. data/spec/macros4cuke/formatter/to-gherkin_spec.rb +129 -0
  24. data/spec/macros4cuke/formatter/to-null_spec.rb +62 -0
  25. data/spec/macros4cuke/formatter/to-trace_spec.rb +155 -0
  26. data/spec/macros4cuke/formatting-service_spec.rb +138 -0
  27. data/spec/macros4cuke/macro-collection_spec.rb +7 -4
  28. data/spec/macros4cuke/macro-step-support_spec.rb +41 -24
  29. data/spec/macros4cuke/macro-step_spec.rb +13 -6
  30. data/spec/macros4cuke/templating/engine_spec.rb +11 -7
  31. data/spec/macros4cuke/templating/placeholder_spec.rb +1 -1
  32. data/spec/macros4cuke/templating/section_spec.rb +3 -1
  33. data/spec/macros4cuke/use-sample-collection.rb +79 -0
  34. data/spec/spec_helper.rb +3 -0
  35. metadata +15 -2
@@ -23,6 +23,9 @@ class MacroStep
23
23
  # A template engine that expands the sub-steps upon request.
24
24
  attr_reader(:renderer)
25
25
 
26
+ # The sentence fragment that defines the syntax of the macro-step
27
+ attr_reader(:phrase)
28
+
26
29
  # Unique key of the macro as derived from the macro phrase.
27
30
  attr_reader(:key)
28
31
 
@@ -30,7 +33,7 @@ class MacroStep
30
33
  attr_reader(:phrase_args)
31
34
 
32
35
  # The list of macro argument names (as appearing in the substeps
33
- # and in the macro phrase).
36
+ # AND in the macro phrase).
34
37
  attr_reader(:args)
35
38
 
36
39
  # Constructor.
@@ -41,15 +44,12 @@ class MacroStep
41
44
  # @param useTable [boolean] A flag indicating whether a data table
42
45
  # must be used to pass actual values.
43
46
  def initialize(aMacroPhrase, theSubsteps, useTable)
47
+ @phrase = aMacroPhrase
44
48
  @key = self.class.macro_key(aMacroPhrase, useTable, :definition)
45
49
 
46
50
  # Retrieve the macro arguments embedded in the phrase.
47
51
  @phrase_args = scan_arguments(aMacroPhrase, :definition)
48
-
49
- # Manipulate the substeps source text
50
- substeps_processed = preprocess(theSubsteps)
51
-
52
- @renderer = Templating::Engine.new(substeps_processed)
52
+ @renderer = Templating::Engine.new(theSubsteps)
53
53
  substeps_vars = renderer.variables
54
54
 
55
55
 
@@ -165,17 +165,15 @@ private
165
165
  # @param params [Hash] The pairs phrase argument name => value
166
166
  def validate_row(a_row, params)
167
167
  (a_key, value) = a_row
168
- raise UnknownArgumentError.new(a_key) unless args.include? a_key
168
+ fail(UnknownArgumentError.new(a_key)) unless args.include? a_key
169
169
  if (phrase_args.include? a_key) && (params[a_key] != value)
170
- raise AmbiguousArgumentValue.new(a_key, params[a_key], value)
170
+ fail(AmbiguousArgumentValue.new(a_key, params[a_key], value))
171
171
  end
172
172
 
173
173
  return a_row
174
174
  end
175
175
 
176
176
 
177
-
178
-
179
177
  # Retrieve from the macro phrase, all the text between <..> or double quotes.
180
178
  # Returns an array. Each of its elements corresponds to quoted text.
181
179
  # Example:
@@ -201,20 +199,6 @@ private
201
199
 
202
200
  return args
203
201
  end
204
-
205
- # Return the substeps text after some transformation
206
- # [theSubstepsSource] The source text of the steps
207
- # to be expanded upon macro invokation.
208
- def preprocess(theSubstepsSource)
209
- # Split text into lines
210
- lines = theSubstepsSource.split(/\r\n?|\n/)
211
-
212
- # Reject comment lines. This is necessary because
213
- # Cucumber::RbSupport::RbWorld#steps complains when it sees a comment.
214
- processed = lines.reject { |a_line| a_line =~ /\s*#/ }
215
-
216
- return processed.join("\n")
217
- end
218
202
 
219
203
  # Check for inconsistencies between the argument names
220
204
  # in the phrase and the substeps part.
@@ -222,7 +206,7 @@ private
222
206
  # Error when the phrase names an argument that never occurs in the substeps
223
207
  thePhraseArgs.each do |phrase_arg|
224
208
  unless substepsVars.include? phrase_arg
225
- raise UselessPhraseArgument.new(phrase_arg)
209
+ fail(UselessPhraseArgument.new(phrase_arg))
226
210
  end
227
211
  end
228
212
  # Error when a substep has an argument that never appears in the phrase
@@ -231,7 +215,7 @@ private
231
215
  substepsVars.each do |substep_arg|
232
216
  unless thePhraseArgs.include?(substep_arg) ||
233
217
  BuiltinParameters.include?(substep_arg)
234
- raise UnreachableSubstepArgument.new(substep_arg)
218
+ fail(UnreachableSubstepArgument.new(substep_arg))
235
219
  end
236
220
  end
237
221
  end
@@ -38,6 +38,34 @@ class StaticText
38
38
  end # class
39
39
 
40
40
 
41
+ # Class used internally by the template engine.
42
+ # Represents a comment from a template.
43
+ # A static text is a text that is reproduced verbatim
44
+ # when rendering a template.
45
+ class Comment
46
+ # The comment as extracted from the original template.
47
+ attr_reader(:source)
48
+
49
+
50
+ # @param aSourceText [String] A piece of text extracted
51
+ # from the template that must be rendered verbatim.
52
+ def initialize(aSourceText)
53
+ @source = aSourceText
54
+ end
55
+
56
+ public
57
+
58
+ # Render the comment.
59
+ # Comments are rendered as empty text. This is necessary because
60
+ # Cucumber::RbSupport::RbWorld#steps complains when it sees a comment.
61
+ # This method has the same signature as the {Engine#render} method.
62
+ # @return [String] Empty string ("as is")
63
+ def render(aContextObject, theLocals)
64
+ return ''
65
+ end
66
+ end # class
67
+
68
+
41
69
  # Class used internally by the template engine.
42
70
  # Represents an end of line that must be rendered as such.
43
71
  class EOLine
@@ -160,7 +188,7 @@ class Section < UnaryElement
160
188
  # Returns an empty string when no value is assigned to the placeholder.
161
189
  def render(aContextObject, theLocals)
162
190
  msg = "Method Section.#{__method__} must be implemented in subclass."
163
- raise NotImplementedError, msg
191
+ fail(NotImplementedError, msg)
164
192
  end
165
193
 
166
194
  end # class
@@ -239,6 +267,9 @@ class Engine
239
267
  # The original text of the template is kept here.
240
268
  attr_reader(:source)
241
269
 
270
+ # The internal representation of the template text
271
+ attr_reader(:representation)
272
+
242
273
  # Builds an Engine and compiles the given template text into
243
274
  # an internal representation.
244
275
  # @param aSourceTemplate [String] The template source text.
@@ -260,11 +291,19 @@ public
260
291
  # the passed argument values.
261
292
  def render(aContextObject = Object.new, theLocals)
262
293
  return '' if @representation.empty?
263
-
294
+
295
+ prev = nil
264
296
  result = @representation.each_with_object('') do |element, subResult|
265
- subResult << element.render(aContextObject, theLocals)
297
+ # Output compaction rules:
298
+ # -In case of consecutive eol's only one is rendered.
299
+ # -In case of comment followed by one eol, both aren't rendered
300
+ unless element.is_a?(EOLine) &&
301
+ (prev.is_a?(EOLine) || prev.is_a?(Comment))
302
+ subResult << element.render(aContextObject, theLocals)
303
+ end
304
+ prev = element
266
305
  end
267
-
306
+
268
307
  return result
269
308
  end
270
309
 
@@ -295,24 +334,28 @@ public
295
334
 
296
335
  # Class method. Parse the given line text into a raw representation.
297
336
  # @return [Array] Couples of the form:
298
- # [:static, text] or [:dynamic, tag text]
337
+ # [:static, text], [:comment, text] or [:dynamic, tag text]
299
338
  def self.parse(aTextLine)
300
339
  scanner = StringScanner.new(aTextLine)
301
340
  result = []
302
-
303
- until scanner.eos?
304
- # Scan tag at current position...
305
- tag_literal = scanner.scan(/<(?:[^\\<>]|\\.)*>/)
306
- unless tag_literal.nil?
307
- result << [:dynamic, tag_literal.gsub(/^<|>$/, '')]
341
+
342
+ if scanner.check(/\s*#/) # Detect comment line
343
+ result << [:comment, aTextLine]
344
+ else
345
+ until scanner.eos?
346
+ # Scan tag at current position...
347
+ tag_literal = scanner.scan(/<(?:[^\\<>]|\\.)*>/)
348
+ unless tag_literal.nil?
349
+ result << [:dynamic, tag_literal.gsub(/^<|>$/, '')]
350
+ end
351
+
352
+ # ... or scan plain text at current position
353
+ literal = scanner.scan(/(?:[^\\<>]|\\.)+/)
354
+ result << [:static, literal] unless literal.nil?
355
+ identify_parse_error(aTextLine) if tag_literal.nil? && literal.nil?
308
356
  end
309
-
310
- # ... or scan plain text at current position
311
- text_literal = scanner.scan(/(?:[^\\<>]|\\.)+/)
312
- result << [:static, text_literal] unless text_literal.nil?
313
- identify_parse_error(aTextLine) if tag_literal.nil? && text_literal.nil?
314
357
  end
315
-
358
+
316
359
  return result
317
360
  end
318
361
 
@@ -336,11 +379,11 @@ private
336
379
  when '>' then unbalance -= 1
337
380
  end
338
381
 
339
- raise StandardError, "Nested opening chevron '<'." if unbalance > 1
340
- raise StandardError, "Missing opening chevron '<'." if unbalance < 0
382
+ fail(StandardError, "Nested opening chevron '<'.") if unbalance > 1
383
+ fail(StandardError, "Missing opening chevron '<'.") if unbalance < 0
341
384
  end
342
385
 
343
- raise StandardError, "Missing closing chevron '>'." if unbalance == 1
386
+ fail(StandardError, "Missing closing chevron '>'.") if unbalance == 1
344
387
  end
345
388
 
346
389
 
@@ -355,7 +398,7 @@ private
355
398
  line_items.each do |(kind, text)|
356
399
  # A tag text cannot be empty nor blank
357
400
  if (kind == :dynamic) && text.strip.empty?
358
- raise EmptyArgumentError.new(line.strip)
401
+ fail(EmptyArgumentError.new(line.strip))
359
402
  end
360
403
  end
361
404
 
@@ -390,7 +433,7 @@ private
390
433
  false
391
434
  end
392
435
  end
393
- if line_to_squeeze && ! section_item.nil?
436
+ if line_to_squeeze && !section_item.nil?
394
437
  line_rep = [section_item]
395
438
  else
396
439
  line_rep_ending(line_rep)
@@ -398,7 +441,7 @@ private
398
441
 
399
442
  return line_rep
400
443
  end
401
-
444
+
402
445
 
403
446
  # Apply rule: if last item in line is an end of section marker,
404
447
  # then place eoline before that item.
@@ -418,15 +461,17 @@ private
418
461
  # Where kind must be one of :static, :dynamic
419
462
  def compile_couple(aCouple)
420
463
  (kind, text) = aCouple
421
-
464
+
422
465
  result = case kind
423
466
  when :static then StaticText.new(text)
467
+ when :comment then Comment.new(text)
424
468
  when :dynamic then parse_tag(text)
425
469
  end
426
470
 
427
471
  return result
428
472
  end
429
-
473
+
474
+
430
475
  # Parse the contents of a tag entry.
431
476
  # @param aText [String] The text that is enclosed between chevrons.
432
477
  def parse_tag(aText)
@@ -437,7 +482,7 @@ private
437
482
  # Disallow punctuation and delimiter signs in tags.
438
483
  matching = DisallowedSigns.match(aText)
439
484
  end
440
- raise InvalidCharError.new(aText, matching[0]) if matching
485
+ fail(InvalidCharError.new(aText, matching[0])) if matching
441
486
 
442
487
  result = case aText[0, 1]
443
488
  when '?'
@@ -477,7 +522,7 @@ private
477
522
 
478
523
  unless open_sections.empty?
479
524
  error_message = "Unterminated section #{open_sections.last}."
480
- raise StandardError, error_message
525
+ fail(StandardError, error_message)
481
526
  end
482
527
 
483
528
  return compiled
@@ -490,11 +535,11 @@ private
490
535
 
491
536
  if sections.empty?
492
537
  msg = 'found while no corresponding section is open.'
493
- raise StandardError, msg_prefix + msg
538
+ fail(StandardError, msg_prefix + msg)
494
539
  end
495
540
  if marker.name != sections.last.name
496
541
  msg = "doesn't match current section '#{sections.last.name}'."
497
- raise StandardError, msg_prefix + msg
542
+ fail(StandardError, msg_prefix + msg)
498
543
  end
499
544
  end
500
545
 
@@ -0,0 +1,269 @@
1
+ # File: collection-walker_spec.rb
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ # Load mix-in module for creating a sample collection of macro-steps
6
+ require_relative 'use-sample-collection'
7
+
8
+ # Load the class under test
9
+ require_relative '../../lib/macros4cuke/coll-walker-factory'
10
+
11
+ module Macros4Cuke # Open this namespace to avoid module qualifier prefixes
12
+
13
+ describe CollWalkerFactory do
14
+ include UseSampleCollection # Add convenience methods for sample collection
15
+
16
+
17
+ before(:all) do
18
+ # Fill the collection of macro-steps with sample steps
19
+ fill_collection
20
+ end
21
+
22
+ after(:all) do
23
+ # Clear the collection to prevent interference between spec files
24
+ macro_coll.clear
25
+ end
26
+
27
+ context 'Initialization:' do
28
+ it 'should be created without parameter' do
29
+ expect { CollWalkerFactory.new }.not_to raise_error
30
+ end
31
+
32
+ end # context
33
+
34
+ context 'Provided factory services:' do
35
+ # Default factory instantiation
36
+ subject { CollWalkerFactory.new }
37
+
38
+ it 'should build a walker for the given macro collection' do
39
+ walker = subject.build_walker(macro_coll)
40
+ expect(walker).to be_kind_of(Enumerator)
41
+ end
42
+ end # context
43
+
44
+ context 'Provided walker services:' do
45
+ # Default walker instantiation
46
+ subject do
47
+ factory = CollWalkerFactory.new
48
+ factory.build_walker(macro_coll)
49
+ end
50
+
51
+
52
+ it 'should notify the start of the visit of the collection' do
53
+ initial_event = subject.next
54
+ expect(initial_event).to eq([:on_collection, 0, macro_coll])
55
+ end
56
+
57
+ it 'should notify the visit of a first macro step' do
58
+ 1.times { subject.next }
59
+ first_step = subject.next
60
+ step1 = macro_coll.macro_steps.values[0]
61
+ expect(first_step).to eq([:on_step, 1, step1])
62
+ end
63
+
64
+ it 'should notify the visit of the phrase of the first macro step' do
65
+ 2.times { subject.next }
66
+ first_phrase = subject.next
67
+ sample_phrase1 = UseSampleCollection::SamplePhrase1
68
+ expect(first_phrase).to eq([:on_phrase, 2, sample_phrase1, true])
69
+ end
70
+
71
+ it 'should notify the visit of the substeps renderer of the first step' do
72
+ 3.times { subject.next }
73
+ first_step = macro_coll.macro_steps.values[0]
74
+ first_renderer = subject.next
75
+ expectation = [:on_renderer, 2, first_step.renderer]
76
+ expect(first_renderer).to eq(expectation)
77
+ end
78
+
79
+ it 'should notify the visit of the internal representation of substeps' do
80
+ first_step = macro_coll.macro_steps.values[0]
81
+ substep_chunks = first_step.renderer.representation
82
+ 4.times { subject.next }
83
+ text_representation = subject.next
84
+ expectation = [:on_source, 3, first_step.renderer.source]
85
+ expect(text_representation).to eq(expectation)
86
+
87
+ first_substep_piece = subject.next
88
+ expectation = [:on_static_text, 3, substep_chunks[0].source]
89
+ expect(first_substep_piece).to eq(expectation)
90
+
91
+ second_substep_piece = subject.next
92
+ expect(second_substep_piece).to eq([:on_eol, 3, nil])
93
+
94
+ third_substep_piece = subject.next
95
+ expectation = [:on_static_text, 3, substep_chunks[2].source]
96
+ expect(third_substep_piece).to eq(expectation)
97
+
98
+ fourth_substep_piece = subject.next
99
+ expect(fourth_substep_piece).to eq([:on_eol, 3, nil])
100
+
101
+ fifth_substep_piece = subject.next
102
+ expectation = [:on_static_text, 3, substep_chunks[4].source]
103
+ expect(fifth_substep_piece).to eq(expectation)
104
+
105
+ sixth_substep_piece = subject.next
106
+ expectation = [:on_placeholder, 3, substep_chunks[5].name]
107
+ expect(sixth_substep_piece).to eq(expectation)
108
+
109
+ seventh_substep_piece = subject.next
110
+ expectation = [:on_static_text, 3, substep_chunks[6].source]
111
+ expect(seventh_substep_piece).to eq(expectation)
112
+
113
+ eighth_substep_piece = subject.next
114
+ expect(eighth_substep_piece).to eq([:on_eol, 3, nil])
115
+
116
+ ninth_substep_piece = subject.next
117
+ expectation = [:on_static_text, 3, substep_chunks[8].source]
118
+ expect(ninth_substep_piece).to eq(expectation)
119
+
120
+ tenth_substep_piece = subject.next
121
+ expectation = [:on_placeholder, 3, substep_chunks[9].name]
122
+ expect(tenth_substep_piece).to eq(expectation)
123
+
124
+ eleventh_substep_piece = subject.next
125
+ expectation = [:on_static_text, 3, substep_chunks[10].source]
126
+ expect(eleventh_substep_piece).to eq(expectation)
127
+
128
+ twelfth_substep_piece = subject.next
129
+ expect(twelfth_substep_piece).to eq([:on_eol, 3, nil])
130
+
131
+ thirtieth_substep_piece = subject.next
132
+ expectation = [:on_static_text, 3, substep_chunks[12].source]
133
+ expect(thirtieth_substep_piece).to eq(expectation)
134
+
135
+ fourteenth_substep_piece = subject.next
136
+ expect(fourteenth_substep_piece).to eq([:on_eol, 3, nil])
137
+
138
+ fifteenth_substep_piece = subject.next
139
+ expect(fifteenth_substep_piece).to eq([:on_renderer_end, 2, nil])
140
+ end
141
+
142
+ it 'should notify the visit of a following macro step' do
143
+ (4 + 15 + 1).times { subject.next }
144
+ end_step = subject.next
145
+ expect(end_step).to eq([:on_step_end, 1, nil])
146
+ a_step = subject.next
147
+ expect(a_step).to eq([:on_step, 1, macro_coll.macro_steps.values[1]])
148
+ end
149
+
150
+ it 'should notify the visit of the phrase of a following macro step' do
151
+ (4 + 16 + 2).times { subject.next }
152
+ phrase = subject.next
153
+ sample_phrase = UseSampleCollection::SamplePhrase2
154
+ expect(phrase).to eq([:on_phrase, 2, sample_phrase, true])
155
+ end
156
+
157
+ it 'should notify the visit of the substeps of a following step' do
158
+ (4 + 16 + 3).times { subject.next }
159
+ a_renderer = subject.next
160
+ second_step = macro_coll.macro_steps.values[1]
161
+ expect(a_renderer).to eq([:on_renderer, 2, second_step.renderer])
162
+ end
163
+
164
+ it 'should notify the visit in substeps of following step' do
165
+ second_step = macro_coll.macro_steps.values[1]
166
+ substep_chunks = second_step.renderer.representation.dup
167
+ substep_chunks.map! do |ck|
168
+ if ck.kind_of?(Templating::Section)
169
+ [ck, ck.children, ck].flatten
170
+ else
171
+ ck
172
+ end
173
+ end
174
+ substep_chunks.flatten!
175
+
176
+ (4 + 16 + 4).times { subject.next }
177
+ substeps_text = subject.next
178
+ expectation = [:on_source, 3, second_step.renderer.source]
179
+ expect(substeps_text).to eq(expectation)
180
+
181
+ first_substep_piece = subject.next
182
+ expectation = [:on_static_text, 3, substep_chunks[0].source]
183
+ expect(first_substep_piece).to eq(expectation)
184
+
185
+ [
186
+ [:on_placeholder, 3, :name], # 0
187
+ [:on_static_text, 3, :source], # 1
188
+ [:on_eol, 3, nil], # 2
189
+ [:on_static_text, 3, :source], # 3
190
+ [:on_placeholder, 3, :name], # 4
191
+ [:on_static_text, 3, :source], # 5
192
+ [:on_eol, 3, nil], # 6
193
+ [:on_static_text, 3, :source], # 7
194
+ [:on_placeholder, 3, :name], # 8
195
+ [:on_static_text, 3, :source], # 9
196
+ [:on_eol, 3, nil], # 10
197
+ [:on_static_text, 3, :source], # 11
198
+ [:on_placeholder, 3, :name], # 12
199
+ [:on_static_text, 3, :source], # 13
200
+ [:on_eol, 3, nil], # 14
201
+ [:on_static_text, 3, :source], # 15
202
+ [:on_placeholder, 3, :name], # 16
203
+ [:on_static_text, 3, :source], # 17
204
+ [:on_eol, 3, nil], # 18
205
+ [:on_static_text, 3, :source], # 19
206
+ [:on_placeholder, 3, :name], # 20
207
+ [:on_static_text, 3, :source], # 21
208
+ [:on_eol, 3, nil], # 22
209
+ [:on_eol, 3, nil], # 23
210
+ [:on_comment, 3, :source], # 24
211
+ [:on_eol, 3, nil], # 25
212
+ [:on_comment, 3, :source], # 26
213
+ [:on_eol, 3, nil], # 27
214
+ [:on_comment, 3, :source], # 28
215
+ [:on_eol, 3, nil], # 29
216
+ [:on_section, 3, :name], # 30
217
+ [:on_static_text, 4, :source], # 31
218
+ [:on_placeholder, 4, :name], # 32
219
+ [:on_static_text, 4, :source], # 33
220
+ [:on_eol, 4, nil], # 34
221
+ [:on_section_end, 3, nil], # 35
222
+ [:on_eol, 3, nil], # 36
223
+ [:on_comment, 3, :source], # 37
224
+ [:on_eol, 3, nil], # 38
225
+ [:on_comment, 3, :source], # 39
226
+ [:on_eol, 3, nil], # 40
227
+ [:on_comment, 3, :source], # 41
228
+ [:on_eol, 3, nil], # 42
229
+ [:on_section, 3, :name], # 43
230
+ [:on_static_text, 4, :source], # 44
231
+ [:on_placeholder, 4, :name], # 45
232
+ [:on_static_text, 4, :source], # 46
233
+ [:on_eol, 4, nil], # 47
234
+ [:on_section_end, 3, nil], # 48
235
+ [:on_static_text, 3, :source], # 49
236
+ [:on_eol, 3, nil], # 50
237
+ [:on_renderer_end, 2, nil], # 51
238
+ [:on_step_end, 1, nil], # 52
239
+ [:on_collection_end, 0, nil] # 53
240
+ ].each_with_index do |event, i|
241
+ actual = subject.next
242
+ expect(actual[0]).to eq(event[0])
243
+ expect(actual[1]).to eq(event[1])
244
+ unless event[2].nil?
245
+ expected_obj = substep_chunks[i + 1]
246
+ expect(actual[2]).to eq(expected_obj.send(event[2]))
247
+ end
248
+ end
249
+ expect { subject.next }.to raise_error(StopIteration)
250
+
251
+ end
252
+
253
+ # Must be last test script since it pollutes the macro-collection
254
+ it 'should complain when visiting an unsupported node' do
255
+ first_step = macro_coll.macro_steps.values[0]
256
+ first_step.renderer.representation.insert(2, :not_a_valid_element)
257
+ err_type = Macros4Cuke::InternalError
258
+ err_msg = "Don't know how to format a Symbol."
259
+ expect { subject.each { |x| } }.to raise_error(err_type, err_msg)
260
+ end
261
+
262
+ end # context
263
+
264
+ end # describe
265
+
266
+ end # module
267
+
268
+
269
+ # End of file