aslakhellesoy-cucumber 0.3.0 → 0.3.0.1

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 (49) hide show
  1. data/History.txt +18 -1
  2. data/Manifest.txt +15 -1
  3. data/config/hoe.rb +5 -4
  4. data/examples/i18n/hu/Rakefile +6 -0
  5. data/examples/i18n/hu/features/addition.feature +16 -0
  6. data/examples/i18n/hu/features/division.feature +9 -0
  7. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  8. data/examples/i18n/hu/lib/calculator.rb +14 -0
  9. data/examples/i18n/lv/Rakefile +6 -0
  10. data/examples/i18n/lv/features/addition.feature +16 -0
  11. data/examples/i18n/lv/features/division.feature +9 -0
  12. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  13. data/examples/i18n/lv/lib/calculator.rb +14 -0
  14. data/examples/self_test/features/multiline_name.feature +27 -0
  15. data/examples/tickets/Rakefile +3 -3
  16. data/examples/tickets/features/272/hooks.feature +26 -0
  17. data/examples/tickets/features/272/hooks_steps.rb +53 -0
  18. data/features/cucumber_cli.feature +32 -2
  19. data/features/multiline_names.feature +43 -0
  20. data/features/report_called_undefined_steps.feature +1 -1
  21. data/features/usage.feature +4 -0
  22. data/lib/cucumber/ast/background.rb +3 -6
  23. data/lib/cucumber/ast/feature_element.rb +18 -9
  24. data/lib/cucumber/ast/outline_table.rb +10 -0
  25. data/lib/cucumber/ast/scenario.rb +16 -1
  26. data/lib/cucumber/ast/scenario_outline.rb +1 -1
  27. data/lib/cucumber/ast/step.rb +4 -2
  28. data/lib/cucumber/ast/step_collection.rb +9 -1
  29. data/lib/cucumber/ast/table.rb +4 -0
  30. data/lib/cucumber/formatter/console.rb +1 -1
  31. data/lib/cucumber/formatter/html.rb +1 -1
  32. data/lib/cucumber/formatter/pretty.rb +7 -8
  33. data/lib/cucumber/languages.yml +30 -0
  34. data/lib/cucumber/parser/feature.rb +196 -10
  35. data/lib/cucumber/parser/feature.tt +26 -10
  36. data/lib/cucumber/rails/world.rb +6 -0
  37. data/lib/cucumber/step_mother.rb +2 -1
  38. data/lib/cucumber/version.rb +1 -1
  39. data/lib/cucumber/world.rb +2 -2
  40. data/rails_generators/cucumber/templates/paths.rb +11 -13
  41. data/rails_generators/feature/feature_generator.rb +1 -1
  42. data/spec/cucumber/ast/feature_element_spec.rb +35 -0
  43. data/spec/cucumber/ast/table_spec.rb +6 -2
  44. data/spec/cucumber/cli/configuration_spec.rb +0 -9
  45. data/spec/cucumber/cli/main_spec.rb +55 -153
  46. data/spec/cucumber/parser/feature_parser_spec.rb +79 -0
  47. data/spec/cucumber/step_mother_spec.rb +12 -5
  48. metadata +17 -13
  49. data/spec/cucumber/formatters/profile_formatter_spec.rb +0 -198
@@ -23,7 +23,7 @@ Feature: Cucumber command line
23
23
  2 scenarios
24
24
  2 undefined steps
25
25
 
26
- You can implement step definitions for missing steps with these snippets:
26
+ You can implement step definitions for undefined steps with these snippets:
27
27
 
28
28
  Given /^this does not exist$/ do
29
29
  pending
@@ -9,6 +9,10 @@ Feature: Cucumber command line
9
9
  """
10
10
  /^passing without a table$/ # features/step_definitions/sample_steps.rb:12
11
11
  Given passing without a table # features/background/failing_background_after_success.feature:4
12
+ Given passing without a table # features/multiline_name.feature:6
13
+ Given passing without a table # features/multiline_name.feature:11
14
+ Given <state> without a table # features/multiline_name.feature:16
15
+ Given <state> without a table # features/multiline_name.feature:22
12
16
  Given <state> without a table # features/outline_sample.feature:6
13
17
  Given <other_state> without a table # features/outline_sample.feature:7
14
18
  /^failing without a table$/ # features/step_definitions/sample_steps.rb:15
@@ -23,7 +23,7 @@ module Cucumber
23
23
 
24
24
  def accept(visitor)
25
25
  visitor.visit_comment(@comment)
26
- visitor.visit_background_name(@keyword, @name, file_colon_line(@line), source_indent(text_length))
26
+ visitor.visit_background_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
27
27
  visitor.step_mother.before(self)
28
28
  visitor.visit_steps(@step_invocations)
29
29
  @failed = @step_invocations.detect{|step_invocation| step_invocation.exception}
@@ -43,12 +43,9 @@ module Cucumber
43
43
  @failed
44
44
  end
45
45
 
46
- def text_length
47
- @keyword.jlength
48
- end
49
-
50
46
  def to_sexp
51
47
  sexp = [:background, @line, @keyword]
48
+ sexp += [@name] unless @name.empty?
52
49
  comment = @comment.to_sexp
53
50
  sexp += [comment] if comment
54
51
  steps = @steps.to_sexp
@@ -57,4 +54,4 @@ module Cucumber
57
54
  end
58
55
  end
59
56
  end
60
- end
57
+ end
@@ -1,3 +1,5 @@
1
+ require 'enumerator'
2
+
1
3
  module Cucumber
2
4
  module FeatureElement
3
5
  def attach_steps(steps)
@@ -9,7 +11,21 @@ module Cucumber
9
11
  end
10
12
 
11
13
  def text_length
12
- @keyword.jlength + @name.jlength
14
+ name_line_lengths.max
15
+ end
16
+
17
+ def first_line_length
18
+ name_line_lengths[0]
19
+ end
20
+
21
+ def name_line_lengths
22
+ if @name.empty?
23
+ [@keyword.jlength]
24
+ else
25
+ @name.split("\n").enum_for(:each_with_index).map do |line, line_number|
26
+ line_number == 0 ? @keyword.jlength + line.jlength : line.jlength + Ast::Step::INDENT - 1 # We -1 as names which are not keyword lines are missing a space between keyword and name
27
+ end
28
+ end
13
29
  end
14
30
 
15
31
  def matches_scenario_names?(scenario_names)
@@ -31,12 +47,5 @@ module Cucumber
31
47
  def accept_hook?(hook)
32
48
  @tags.accept_hook?(hook)
33
49
  end
34
-
35
- # TODO: Remove when we use StepCollection everywhere
36
- def previous_step(step)
37
- i = @steps.index(step) || -1
38
- @steps[i-1]
39
- end
40
-
41
50
  end
42
- end
51
+ end
@@ -70,6 +70,16 @@ module Cucumber
70
70
  @table.accept_hook?(hook)
71
71
  end
72
72
 
73
+ # Returns true if one or more steps failed
74
+ def failed?
75
+ @step_invocations.failed?
76
+ end
77
+
78
+ # Returns true if all steps passed
79
+ def passed?
80
+ @step_invocations.passed?
81
+ end
82
+
73
83
  private
74
84
 
75
85
  def header?
@@ -25,7 +25,7 @@ module Cucumber
25
25
  def accept(visitor)
26
26
  visitor.visit_comment(@comment)
27
27
  visitor.visit_tags(@tags)
28
- visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(text_length))
28
+ visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
29
29
 
30
30
  skip = @background && @background.failed?
31
31
  skip_invoke! if skip
@@ -34,6 +34,21 @@ module Cucumber
34
34
  end
35
35
  end
36
36
 
37
+ # Returns true if one or more steps failed
38
+ def failed?
39
+ @steps.failed?
40
+ end
41
+
42
+ # Returns true if all steps passed
43
+ def passed?
44
+ @steps.passed?
45
+ end
46
+
47
+ # Returns the first exception (if any)
48
+ def exception
49
+ @steps.exception
50
+ end
51
+
37
52
  def skip_invoke!
38
53
  @steps.each{|step_invocation| step_invocation.skip_invoke!}
39
54
  @feature.next_feature_element(self) do |next_one|
@@ -33,7 +33,7 @@ module Cucumber
33
33
  def accept(visitor)
34
34
  visitor.visit_comment(@comment)
35
35
  visitor.visit_tags(@tags)
36
- visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(text_length))
36
+ visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
37
37
  visitor.visit_steps(@steps)
38
38
 
39
39
  skip_invoke! if @background && @background.failed?
@@ -8,6 +8,8 @@ module Cucumber
8
8
  attr_writer :step_collection, :options
9
9
  attr_accessor :feature_element, :exception
10
10
 
11
+ INDENT = 2
12
+
11
13
  def initialize(line, keyword, name, multiline_arg=nil)
12
14
  @line, @keyword, @name, @multiline_arg = line, keyword, name, multiline_arg
13
15
  end
@@ -32,7 +34,7 @@ module Cucumber
32
34
 
33
35
  def accept(visitor)
34
36
  # The only time a Step is visited is when it is in a ScenarioOutline.
35
- # Otherwise it's always StepInvocation that gest visited instead.
37
+ # Otherwise it's always StepInvocation that gets visited instead.
36
38
  visit_step_result(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
37
39
  end
38
40
 
@@ -61,7 +63,7 @@ module Cucumber
61
63
  end
62
64
 
63
65
  def text_length
64
- @keyword.jlength + @name.jlength + 2 # Add 2 because steps get indented 2 more than scenarios
66
+ @keyword.jlength + @name.jlength + INDENT # Add indent as steps get indented more than scenarios
65
67
  end
66
68
 
67
69
  def backtrace_line
@@ -54,9 +54,17 @@ module Cucumber
54
54
  @exception ||= ((failed = @steps.detect {|step| step.exception}) && failed.exception)
55
55
  end
56
56
 
57
+ def failed?
58
+ @steps.detect{|step_invocation| step_invocation.status == :failed}
59
+ end
60
+
61
+ def passed?
62
+ @steps.detect{|step_invocation| step_invocation.status != :passed}.nil?
63
+ end
64
+
57
65
  def to_sexp
58
66
  @steps.map{|step| step.to_sexp}
59
67
  end
60
68
  end
61
69
  end
62
- end
70
+ end
@@ -197,6 +197,10 @@ module Cucumber
197
197
  end
198
198
  end
199
199
 
200
+ def headers
201
+ @raw.first
202
+ end
203
+
200
204
  def header_cell(col)
201
205
  cells_rows[0][col]
202
206
  end
@@ -79,7 +79,7 @@ module Cucumber
79
79
  snippet
80
80
  end.compact.uniq
81
81
 
82
- text = "\nYou can implement step definitions for missing steps with these snippets:\n\n"
82
+ text = "\nYou can implement step definitions for undefined steps with these snippets:\n\n"
83
83
  text += snippets.join("\n\n")
84
84
 
85
85
  @io.puts format_string(text, :undefined)
@@ -114,7 +114,7 @@ module Cucumber
114
114
  unless @skip_step
115
115
  step_name = step_match.format_args(lambda{|param| "<span>#{param}</span>"})
116
116
  @builder.div do |div|
117
- div << h("#{keyword} #{step_name}")
117
+ div << h("#{keyword} #{step_name}").gsub(/&lt;span&gt;/, '<span>').gsub(/&lt;\/span&gt;/, '</span>')
118
118
  end
119
119
  end
120
120
  end
@@ -95,7 +95,9 @@ module Cucumber
95
95
  end
96
96
 
97
97
  def visit_examples_name(keyword, name)
98
- @io.puts("\n #{keyword} #{name}")
98
+ names = name.empty? ? [name] : name.split("\n")
99
+ @io.puts("\n #{keyword} #{names[0]}")
100
+ names[1..-1].each {|s| @io.puts " #{s}" }
99
101
  @io.flush
100
102
  @indent = 4
101
103
  end
@@ -105,13 +107,15 @@ module Cucumber
105
107
  end
106
108
 
107
109
  def visit_feature_element_name(keyword, name, file_colon_line, source_indent)
108
- line = " #{keyword} #{name}"
110
+ names = name.empty? ? [name] : name.split("\n")
111
+ line = " #{keyword} #{names[0]}"
109
112
  @io.print(line)
110
113
  if @options[:source]
111
114
  line_comment = " # #{file_colon_line}".indent(source_indent)
112
115
  @io.print(format_string(line_comment, :comment))
113
116
  end
114
117
  @io.puts
118
+ names[1..-1].each {|s| @io.puts " #{s}"}
115
119
  @io.flush
116
120
  end
117
121
 
@@ -126,11 +130,6 @@ module Cucumber
126
130
  @exceptions << exception
127
131
  end
128
132
  return if status != :failed && @in_background ^ background
129
-
130
- # @step_matches ||= []
131
- # return if @step_matches.index(step_match)
132
- # @step_matches << step_match
133
-
134
133
  @status = status
135
134
  super
136
135
  end
@@ -169,7 +168,7 @@ module Cucumber
169
168
 
170
169
  def visit_table_cell_value(value, width, status)
171
170
  status ||= @status || :passed
172
- @io.print(' ' + format_string((value.to_s || '').ljust(width), status) + " #{@delim}")
171
+ @io.print(' ' + format_string((value.to_s || '').ljust(width), status) + ::Term::ANSIColor.reset(" #{@delim}"))
173
172
  @io.flush
174
173
  end
175
174
 
@@ -206,6 +206,21 @@
206
206
  and: Et
207
207
  but: Mais
208
208
  space_after_keyword: true
209
+ "hu":
210
+ name: Hungarian
211
+ native: magyar
212
+ encoding: UTF-8
213
+ feature: Jellemző
214
+ background: Háttér
215
+ scenario: Forgatókönyv
216
+ scenario_outline: Forgatókönyv vázlat
217
+ examples: Példák
218
+ given: Ha
219
+ when: Majd
220
+ then: Akkor
221
+ and: És
222
+ but: De
223
+ space_after_keyword: true
209
224
  "id":
210
225
  name: Indonesian
211
226
  native: Bahasa Indonesia
@@ -264,6 +279,21 @@
264
279
  and: Ir
265
280
  but: Bet
266
281
  space_after_keyword: true
282
+ "lv":
283
+ name: Latvian
284
+ native: latviešu
285
+ encoding: UTF-8
286
+ feature: Funkcionalitāte|Fīča
287
+ background: Konteksts|Situācija
288
+ scenario: Scenārijs
289
+ scenario_outline: Scenārijs pēc parauga
290
+ examples: Piemēri|Paraugs
291
+ given: Kad
292
+ when: Ja
293
+ then: Tad
294
+ and: Un
295
+ but: Bet
296
+ space_after_keyword: true
267
297
  "nl":
268
298
  name: Dutch
269
299
  native: Nederlands
@@ -486,7 +486,7 @@ module Cucumber
486
486
  comment.build,
487
487
  background_keyword.line,
488
488
  background_keyword.text_value,
489
- name.text_value,
489
+ name.build,
490
490
  steps.build
491
491
  )
492
492
  end
@@ -522,7 +522,7 @@ module Cucumber
522
522
  r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
523
523
  s0 << r4
524
524
  if r4
525
- r7 = _nt_line_to_eol
525
+ r7 = _nt_lines_to_keyword
526
526
  if r7
527
527
  r6 = r7
528
528
  else
@@ -679,7 +679,7 @@ module Cucumber
679
679
  end
680
680
 
681
681
  def matches_name?(name_to_match)
682
- name.text_value == name_to_match
682
+ name.build == name_to_match
683
683
  end
684
684
 
685
685
  def build(background, filter)
@@ -689,7 +689,7 @@ module Cucumber
689
689
  tags.build,
690
690
  scenario_keyword.line,
691
691
  scenario_keyword.text_value,
692
- name.text_value,
692
+ name.build,
693
693
  steps.build
694
694
  )
695
695
  end
@@ -728,7 +728,7 @@ module Cucumber
728
728
  r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
729
729
  s0 << r5
730
730
  if r5
731
- r7 = _nt_line_to_eol
731
+ r7 = _nt_lines_to_keyword
732
732
  s0 << r7
733
733
  if r7
734
734
  r8 = _nt_white
@@ -817,7 +817,7 @@ module Cucumber
817
817
  end
818
818
 
819
819
  def matches_name?(name_to_match)
820
- name.text_value == name_to_match
820
+ name.build == name_to_match
821
821
  end
822
822
 
823
823
  def build(background, filter)
@@ -827,7 +827,7 @@ module Cucumber
827
827
  tags.build,
828
828
  scenario_outline_keyword.line,
829
829
  scenario_outline_keyword.text_value,
830
- name.text_value,
830
+ name.build,
831
831
  steps.build,
832
832
  examples_sections.build(filter, self)
833
833
  )
@@ -867,7 +867,7 @@ module Cucumber
867
867
  r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
868
868
  s0 << r5
869
869
  if r5
870
- r7 = _nt_line_to_eol
870
+ r7 = _nt_lines_to_keyword
871
871
  s0 << r7
872
872
  if r7
873
873
  r8 = _nt_white
@@ -1149,7 +1149,7 @@ module Cucumber
1149
1149
  end
1150
1150
 
1151
1151
  def build(filter, scenario_outline)
1152
- [examples_keyword.line, examples_keyword.text_value, name.text_value, table.raw(filter, scenario_outline)]
1152
+ [examples_keyword.line, examples_keyword.text_value, name.build, table.raw(filter, scenario_outline)]
1153
1153
  end
1154
1154
  end
1155
1155
 
@@ -1189,7 +1189,7 @@ module Cucumber
1189
1189
  r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
1190
1190
  s0 << r4
1191
1191
  if r4
1192
- r7 = _nt_line_to_eol
1192
+ r7 = _nt_lines_to_keyword
1193
1193
  if r7
1194
1194
  r6 = r7
1195
1195
  else
@@ -1305,6 +1305,192 @@ module Cucumber
1305
1305
  return r0
1306
1306
  end
1307
1307
 
1308
+ module LineToKeyword0
1309
+ end
1310
+
1311
+ module LineToKeyword1
1312
+ def white
1313
+ elements[0]
1314
+ end
1315
+
1316
+ def text
1317
+ elements[1]
1318
+ end
1319
+ end
1320
+
1321
+ module LineToKeyword2
1322
+ def build
1323
+ text.text_value.strip
1324
+ end
1325
+ end
1326
+
1327
+ def _nt_line_to_keyword
1328
+ start_index = index
1329
+ if node_cache[:line_to_keyword].has_key?(index)
1330
+ cached = node_cache[:line_to_keyword][index]
1331
+ @index = cached.interval.end if cached
1332
+ return cached
1333
+ end
1334
+
1335
+ i0, s0 = index, []
1336
+ r1 = _nt_white
1337
+ s0 << r1
1338
+ if r1
1339
+ s2, i2 = [], index
1340
+ loop do
1341
+ i3, s3 = index, []
1342
+ i4 = index
1343
+ r5 = _nt_step_keyword
1344
+ if r5
1345
+ r4 = nil
1346
+ else
1347
+ self.index = i4
1348
+ r4 = instantiate_node(SyntaxNode,input, index...index)
1349
+ end
1350
+ s3 << r4
1351
+ if r4
1352
+ i6 = index
1353
+ r7 = _nt_scenario_keyword
1354
+ if r7
1355
+ r6 = nil
1356
+ else
1357
+ self.index = i6
1358
+ r6 = instantiate_node(SyntaxNode,input, index...index)
1359
+ end
1360
+ s3 << r6
1361
+ if r6
1362
+ i8 = index
1363
+ r9 = _nt_scenario_outline_keyword
1364
+ if r9
1365
+ r8 = nil
1366
+ else
1367
+ self.index = i8
1368
+ r8 = instantiate_node(SyntaxNode,input, index...index)
1369
+ end
1370
+ s3 << r8
1371
+ if r8
1372
+ i10 = index
1373
+ r11 = _nt_table
1374
+ if r11
1375
+ r10 = nil
1376
+ else
1377
+ self.index = i10
1378
+ r10 = instantiate_node(SyntaxNode,input, index...index)
1379
+ end
1380
+ s3 << r10
1381
+ if r10
1382
+ i12 = index
1383
+ r13 = _nt_tag
1384
+ if r13
1385
+ r12 = nil
1386
+ else
1387
+ self.index = i12
1388
+ r12 = instantiate_node(SyntaxNode,input, index...index)
1389
+ end
1390
+ s3 << r12
1391
+ if r12
1392
+ i14 = index
1393
+ r15 = _nt_comment_line
1394
+ if r15
1395
+ r14 = nil
1396
+ else
1397
+ self.index = i14
1398
+ r14 = instantiate_node(SyntaxNode,input, index...index)
1399
+ end
1400
+ s3 << r14
1401
+ if r14
1402
+ i16 = index
1403
+ r17 = _nt_eol
1404
+ if r17
1405
+ r16 = nil
1406
+ else
1407
+ self.index = i16
1408
+ r16 = instantiate_node(SyntaxNode,input, index...index)
1409
+ end
1410
+ s3 << r16
1411
+ if r16
1412
+ if index < input_length
1413
+ r18 = instantiate_node(SyntaxNode,input, index...(index + 1))
1414
+ @index += 1
1415
+ else
1416
+ terminal_parse_failure("any character")
1417
+ r18 = nil
1418
+ end
1419
+ s3 << r18
1420
+ end
1421
+ end
1422
+ end
1423
+ end
1424
+ end
1425
+ end
1426
+ end
1427
+ if s3.last
1428
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
1429
+ r3.extend(LineToKeyword0)
1430
+ else
1431
+ self.index = i3
1432
+ r3 = nil
1433
+ end
1434
+ if r3
1435
+ s2 << r3
1436
+ else
1437
+ break
1438
+ end
1439
+ end
1440
+ if s2.empty?
1441
+ self.index = i2
1442
+ r2 = nil
1443
+ else
1444
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1445
+ end
1446
+ s0 << r2
1447
+ end
1448
+ if s0.last
1449
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1450
+ r0.extend(LineToKeyword1)
1451
+ r0.extend(LineToKeyword2)
1452
+ else
1453
+ self.index = i0
1454
+ r0 = nil
1455
+ end
1456
+
1457
+ node_cache[:line_to_keyword][start_index] = r0
1458
+
1459
+ return r0
1460
+ end
1461
+
1462
+ module LinesToKeyword0
1463
+
1464
+ def build
1465
+ elements.map{|s| s.build}.join("\n")
1466
+ end
1467
+ end
1468
+
1469
+ def _nt_lines_to_keyword
1470
+ start_index = index
1471
+ if node_cache[:lines_to_keyword].has_key?(index)
1472
+ cached = node_cache[:lines_to_keyword][index]
1473
+ @index = cached.interval.end if cached
1474
+ return cached
1475
+ end
1476
+
1477
+ s0, i0 = [], index
1478
+ loop do
1479
+ r1 = _nt_line_to_keyword
1480
+ if r1
1481
+ s0 << r1
1482
+ else
1483
+ break
1484
+ end
1485
+ end
1486
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1487
+ r0.extend(LinesToKeyword0)
1488
+
1489
+ node_cache[:lines_to_keyword][start_index] = r0
1490
+
1491
+ return r0
1492
+ end
1493
+
1308
1494
  module PyString0
1309
1495
  end
1310
1496