cucumber 0.8.3 → 0.8.4

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 (119) hide show
  1. data/Caliper.yml +0 -1
  2. data/History.txt +9 -0
  3. data/Rakefile +3 -3
  4. data/VERSION.yml +1 -1
  5. data/cucumber.gemspec +93 -106
  6. data/examples/python/README.textile +7 -0
  7. data/examples/rspec_doubles/features/mocking.feature +9 -0
  8. data/examples/rspec_doubles/features/step_definitions/calvin_steps.rb +19 -0
  9. data/examples/rspec_doubles/features/support/env.rb +12 -0
  10. data/examples/ruby2python/README.textile +7 -0
  11. data/examples/watir/features/search.feature +1 -1
  12. data/examples/webrat/features/search.feature +1 -1
  13. data/examples/webrat/features/support/env.rb +2 -2
  14. data/features/background.feature +1 -1
  15. data/features/cucumber_cli.feature +23 -90
  16. data/features/{cucumber_cli_diff_disabled.feature → diffing.feature} +1 -6
  17. data/features/html_formatter.feature +2 -2
  18. data/features/html_formatter/a.html +1 -6
  19. data/features/json_formatter.feature +1 -1
  20. data/features/junit_formatter.feature +5 -5
  21. data/features/language_help.feature +1 -0
  22. data/features/step_definitions/cucumber_steps.rb +2 -2
  23. data/features/support/env.rb +11 -7
  24. data/{examples → fixtures}/json/features/background.feature +0 -0
  25. data/{examples → fixtures}/json/features/embed.feature +0 -0
  26. data/{examples → fixtures}/json/features/one_passing_one_failing.feature +0 -0
  27. data/{examples → fixtures}/json/features/pystring.feature +0 -0
  28. data/{examples → fixtures}/json/features/step_definitions/steps.rb +0 -0
  29. data/{examples → fixtures}/json/features/tables.feature +0 -0
  30. data/{examples → fixtures}/junit/features/one_passing_one_failing.feature +0 -0
  31. data/{examples → fixtures}/junit/features/pending.feature +0 -0
  32. data/{examples → fixtures}/junit/features/step_definitions/steps.rb +0 -0
  33. data/{examples → fixtures}/self_test/.gitignore +0 -0
  34. data/{examples → fixtures}/self_test/README.textile +0 -0
  35. data/{examples → fixtures}/self_test/Rakefile +0 -0
  36. data/{examples → fixtures}/self_test/features/background/background_tagged_before_on_outline.feature +0 -0
  37. data/{examples → fixtures}/self_test/features/background/background_with_name.feature +0 -0
  38. data/{examples → fixtures}/self_test/features/background/failing_background.feature +0 -0
  39. data/{examples → fixtures}/self_test/features/background/failing_background_after_success.feature +0 -0
  40. data/{examples → fixtures}/self_test/features/background/multiline_args_background.feature +0 -0
  41. data/{examples → fixtures}/self_test/features/background/passing_background.feature +0 -0
  42. data/{examples → fixtures}/self_test/features/background/pending_background.feature +0 -0
  43. data/{examples → fixtures}/self_test/features/background/scenario_outline_failing_background.feature +0 -0
  44. data/{examples → fixtures}/self_test/features/background/scenario_outline_passing_background.feature +0 -0
  45. data/{examples → fixtures}/self_test/features/call_undefined_step_from_step_def.feature +0 -0
  46. data/{examples → fixtures}/self_test/features/failing_expectation.feature +0 -0
  47. data/{examples → fixtures}/self_test/features/lots_of_undefined.feature +0 -0
  48. data/{examples → fixtures}/self_test/features/multiline_name.feature +0 -0
  49. data/{examples → fixtures}/self_test/features/outline_sample.feature +0 -0
  50. data/{examples → fixtures}/self_test/features/sample.feature +0 -0
  51. data/{examples → fixtures}/self_test/features/search_sample.feature +0 -0
  52. data/{examples → fixtures}/self_test/features/step_definitions/sample_steps.rb +0 -0
  53. data/{examples → fixtures}/self_test/features/support/env.rb +0 -0
  54. data/{examples → fixtures}/self_test/features/tags_sample.feature +0 -0
  55. data/{examples → fixtures}/self_test/features/tons_of_cukes.feature +0 -0
  56. data/{examples → fixtures}/self_test/features/undefined_multiline_args.feature +0 -0
  57. data/{examples → fixtures}/self_test/list-of-features.txt +0 -0
  58. data/{examples → fixtures}/steps_library/features/step_definitions/steps_lib1.rb +0 -0
  59. data/{examples → fixtures}/steps_library/features/step_definitions/steps_lib2.rb +0 -0
  60. data/{examples → fixtures}/tickets/Rakefile +0 -0
  61. data/{examples → fixtures}/tickets/features.html +0 -0
  62. data/{examples → fixtures}/tickets/features/172.feature +0 -0
  63. data/{examples → fixtures}/tickets/features/177/1.feature +0 -0
  64. data/{examples → fixtures}/tickets/features/177/2.feature +0 -0
  65. data/{examples → fixtures}/tickets/features/177/3.feature +0 -0
  66. data/{examples → fixtures}/tickets/features/180.feature +0 -0
  67. data/{examples → fixtures}/tickets/features/229/tagged_hooks.feature +0 -0
  68. data/{examples → fixtures}/tickets/features/229/tagged_hooks.rb +0 -0
  69. data/{examples → fixtures}/tickets/features/236.feature +0 -0
  70. data/{examples → fixtures}/tickets/features/241.feature +0 -0
  71. data/{examples → fixtures}/tickets/features/246.feature +0 -0
  72. data/{examples → fixtures}/tickets/features/248.feature +0 -0
  73. data/{examples → fixtures}/tickets/features/270/back.feature +0 -0
  74. data/{examples → fixtures}/tickets/features/270/back.steps.rb +0 -0
  75. data/{examples → fixtures}/tickets/features/272/hooks.feature +0 -0
  76. data/{examples → fixtures}/tickets/features/272/hooks_steps.rb +0 -0
  77. data/{examples → fixtures}/tickets/features/279/py_string_indent.feature +0 -0
  78. data/{examples → fixtures}/tickets/features/279/py_string_indent.steps.rb +0 -0
  79. data/{examples → fixtures}/tickets/features/279/wrong.feature_ +0 -0
  80. data/{examples → fixtures}/tickets/features/301/filter_background_tagged_hooks.feature +0 -0
  81. data/{examples → fixtures}/tickets/features/301/filter_background_tagged_hooks_steps.rb +0 -0
  82. data/{examples → fixtures}/tickets/features/306/only_background.feature +0 -0
  83. data/{examples → fixtures}/tickets/features/around_timeout.feature +0 -0
  84. data/{examples → fixtures}/tickets/features/half_manual.feature +0 -0
  85. data/{examples → fixtures}/tickets/features/lib/eatting_machine.rb +0 -0
  86. data/{examples → fixtures}/tickets/features/lib/pantry.rb +0 -0
  87. data/{examples → fixtures}/tickets/features/scenario_outline.feature +0 -0
  88. data/{examples → fixtures}/tickets/features/step_definitons/246_steps.rb +0 -0
  89. data/{examples → fixtures}/tickets/features/step_definitons/248_steps.rb +0 -0
  90. data/{examples → fixtures}/tickets/features/step_definitons/around_timeout_steps.rb +0 -0
  91. data/{examples → fixtures}/tickets/features/step_definitons/half_manual_steps.rb +0 -0
  92. data/{examples → fixtures}/tickets/features/step_definitons/scenario_outline_steps.rb +0 -0
  93. data/{examples → fixtures}/tickets/features/step_definitons/tickets_steps.rb +0 -0
  94. data/{examples → fixtures}/tickets/features/table_diffing.feature +0 -0
  95. data/{examples → fixtures}/tickets/features/tickets.feature +0 -0
  96. data/gem_tasks/examples.rake +1 -1
  97. data/lib/cucumber/ast/feature.rb +0 -5
  98. data/lib/cucumber/ast/feature_element.rb +2 -6
  99. data/lib/cucumber/ast/features.rb +0 -5
  100. data/lib/cucumber/ast/table.rb +1 -4
  101. data/lib/cucumber/ast/tags.rb +2 -2
  102. data/lib/cucumber/cli/configuration.rb +2 -2
  103. data/lib/cucumber/cli/drb_client.rb +1 -1
  104. data/lib/cucumber/cli/main.rb +1 -17
  105. data/lib/cucumber/cli/options.rb +0 -1
  106. data/lib/cucumber/cli/profile_loader.rb +1 -1
  107. data/lib/cucumber/feature_file.rb +9 -11
  108. data/lib/cucumber/formatter/console.rb +0 -11
  109. data/lib/cucumber/formatter/json.rb +1 -1
  110. data/lib/cucumber/formatter/pretty.rb +0 -1
  111. data/lib/cucumber/formatter/progress.rb +0 -1
  112. data/lib/cucumber/parser/gherkin_builder.rb +34 -28
  113. data/lib/cucumber/rspec/doubles.rb +16 -0
  114. data/lib/cucumber/step_mother.rb +37 -31
  115. data/spec/cucumber/cli/configuration_spec.rb +2 -2
  116. data/spec/cucumber/formatter/spec_helper.rb +1 -1
  117. metadata +96 -109
  118. data/examples/dos_line_endings/Rakefile +0 -6
  119. data/examples/dos_line_endings/features/dos_line_endings.feature +0 -9
@@ -1,7 +1,7 @@
1
1
  desc 'Run all exmples'
2
2
  task :examples do
3
3
  Dir['examples/*'].each do |example_dir|
4
- next if !File.directory?(example_dir) || %w{examples/junit examples/i18n examples/python examples/ruby2python examples/self_test examples/steps_library examples/tickets}.index(example_dir)
4
+ next if !File.directory?(example_dir) || %w{examples/i18n examples/python examples/ruby2python}.index(example_dir)
5
5
  puts "Running #{example_dir}"
6
6
  Dir.chdir(example_dir) do
7
7
  sh "rake cucumber"
@@ -73,11 +73,6 @@ module Cucumber
73
73
  "#{@file}:#{line}"
74
74
  end
75
75
 
76
- def tag_locations(tag)
77
- init
78
- @feature_elements.select{|feature_element| feature_element.tagged_with?(tag)}
79
- end
80
-
81
76
  def short_name
82
77
  first_line = name.split(/\n/)[0]
83
78
  if first_line =~ /#{language.keywords('feature')}:(.*)/
@@ -1,5 +1,5 @@
1
1
  require 'enumerator'
2
- require 'gherkin/parser/tag_expression'
2
+ require 'gherkin/tag_expression'
3
3
 
4
4
  module Cucumber
5
5
  module Ast
@@ -58,17 +58,13 @@ module Cucumber
58
58
  end
59
59
 
60
60
  def accept_hook?(hook)
61
- Gherkin::Parser::TagExpression.new(hook.tag_expressions).eval(source_tag_names)
61
+ Gherkin::TagExpression.new(hook.tag_expressions).eval(source_tag_names)
62
62
  end
63
63
 
64
64
  def source_tag_names
65
65
  (@tags.tag_names.to_a + (@feature ? @feature.source_tag_names.to_a : [])).uniq
66
66
  end
67
67
 
68
- def tagged_with?(tag)
69
- source_tag_names.index(tag)
70
- end
71
-
72
68
  def language
73
69
  @feature.language if @feature
74
70
  end
@@ -30,11 +30,6 @@ module Cucumber
30
30
  end
31
31
  @duration = Time.now - start
32
32
  end
33
-
34
- def tag_locations(tag)
35
- @features.map{|feature| feature.tag_locations(tag)}.flatten
36
- end
37
-
38
33
  end
39
34
  end
40
35
  end
@@ -39,9 +39,6 @@ module Cucumber
39
39
  @rows = []
40
40
  end
41
41
 
42
- def location(uri, offset)
43
- end
44
-
45
42
  def row(row, line_number)
46
43
  @rows << row
47
44
  end
@@ -64,7 +61,7 @@ module Cucumber
64
61
  def self.parse(text, uri, offset)
65
62
  builder = Builder.new
66
63
  lexer = Gherkin::I18nLexer.new(builder)
67
- lexer.scan(text, uri, offset)
64
+ lexer.scan(text)
68
65
  new(builder.rows)
69
66
  end
70
67
 
@@ -1,4 +1,4 @@
1
- require 'gherkin/parser/tag_expression'
1
+ require 'gherkin/tag_expression'
2
2
 
3
3
  module Cucumber
4
4
  module Ast
@@ -17,7 +17,7 @@ module Cucumber
17
17
  end
18
18
 
19
19
  def accept_hook?(hook)
20
- Gherkin::Parser::TagExpression.new(hook.tag_expressions).eval(@tag_names)
20
+ Gherkin::TagExpression.new(hook.tag_expressions).eval(@tag_names)
21
21
  end
22
22
 
23
23
  def to_sexp
@@ -1,7 +1,7 @@
1
1
  require 'logger'
2
2
  require 'cucumber/cli/options'
3
3
  require 'cucumber/constantize'
4
- require 'gherkin/parser/tag_expression'
4
+ require 'gherkin/tag_expression'
5
5
 
6
6
  module Cucumber
7
7
  module Cli
@@ -26,7 +26,7 @@ module Cucumber
26
26
  arrange_formats
27
27
  raise("You can't use both --strict and --wip") if strict? && wip?
28
28
 
29
- @options[:tag_expression] = Gherkin::Parser::TagExpression.new(@options[:tag_expressions])
29
+ @options[:tag_expression] = Gherkin::TagExpression.new(@options[:tag_expressions])
30
30
  return @args.replace(@options.expanded_args_without_drb) if drb?
31
31
 
32
32
  set_environment_variables
@@ -29,7 +29,7 @@ module Cucumber
29
29
  # See http://redmine.ruby-lang.org/issues/show/496 as to why we specify localhost:0
30
30
  begin
31
31
  DRb.start_service("druby://localhost:0")
32
- rescue SocketError
32
+ rescue SocketError, Errno::EADDRNOTAVAIL
33
33
  # Ruby-1.8.7 on snow leopard doesn't like localhost:0 - but just :0
34
34
  # seems to work just fine
35
35
  DRb.start_service("druby://:0")
@@ -55,17 +55,12 @@ module Cucumber
55
55
  features = step_mother.load_plain_text_features(configuration.feature_files)
56
56
  step_mother.load_code_files(configuration.step_defs_to_load)
57
57
 
58
- tag_excess = tag_excess(features)
59
- configuration.options[:tag_excess] = tag_excess # Hack to make it available in console.rb - later: stick on Run instance.
60
-
61
58
  runner = configuration.build_runner(step_mother, @out_stream)
62
59
  step_mother.visitor = runner # Needed to support World#announce
63
60
 
64
61
  runner.visit_features(features)
65
62
 
66
- failure = if tag_excess.any?
67
- true
68
- elsif configuration.wip?
63
+ failure = if configuration.wip?
69
64
  step_mother.scenarios(:passed).any?
70
65
  else
71
66
  step_mother.scenarios(:failed).any? ||
@@ -76,17 +71,6 @@ module Cucumber
76
71
  true
77
72
  end
78
73
 
79
- def tag_excess(features)
80
- configuration.options[:tag_expression].limits.map do |tag_name, tag_limit|
81
- tag_locations = features.tag_locations(tag_name)
82
- if tag_limit && (tag_locations.length > tag_limit)
83
- [tag_name, tag_limit, tag_locations]
84
- else
85
- nil
86
- end
87
- end.compact
88
- end
89
-
90
74
  def configuration
91
75
  return @configuration if @configuration
92
76
 
@@ -1,6 +1,5 @@
1
1
  require 'cucumber/cli/profile_loader'
2
2
  require 'cucumber/formatter/ansicolor'
3
- require 'gherkin/parser/tag_expression'
4
3
 
5
4
  module Cucumber
6
5
  module Cli
@@ -52,7 +52,7 @@ Defined profiles in cucumber.yml:
52
52
  def cucumber_yml
53
53
  return @cucumber_yml if @cucumber_yml
54
54
  unless cucumber_yml_defined?
55
- raise(ProfilesNotDefinedError,"cucumber.yml was not found. Please refer to cucumber's documentation on defining profiles in cucumber.yml. You must define a 'default' profile to use the cucumber command without any arguments.\nType 'cucumber --help' for usage.\n")
55
+ raise(ProfilesNotDefinedError,"cucumber.yml was not found. Current directory is #{Dir.pwd}. Please refer to cucumber's documentation on defining profiles in cucumber.yml. You must define a 'default' profile to use the cucumber command without any arguments.\nType 'cucumber --help' for usage.\n")
56
56
  end
57
57
 
58
58
  require 'erb'
@@ -1,6 +1,6 @@
1
1
  require 'cucumber/parser/gherkin_builder'
2
- require 'gherkin/parser/filter_listener'
3
- require 'gherkin/parser/formatter_listener'
2
+ require 'gherkin/formatter/filter_formatter'
3
+ require 'gherkin/formatter/tag_count_formatter'
4
4
  require 'gherkin/parser/parser'
5
5
  require 'gherkin/i18n_lexer'
6
6
 
@@ -24,21 +24,19 @@ module Cucumber
24
24
  # Parses a file and returns a Cucumber::Ast
25
25
  # If +options+ contains tags, the result will
26
26
  # be filtered.
27
- def parse(step_mother, options)
27
+ def parse(options, tag_counts)
28
28
  filters = @lines || options.filters
29
29
 
30
- builder = Cucumber::Parser::GherkinBuilder.new
31
- formatter_listener = Gherkin::Parser::FormatterListener.new(builder)
32
- filter_listener = Gherkin::Parser::FilterListener.new(formatter_listener, filters)
33
- parser = Gherkin::Parser::Parser.new(filter_listener, true, "root")
34
- lexer = Gherkin::I18nLexer.new(parser, false)
30
+ builder = Cucumber::Parser::GherkinBuilder.new
31
+ filter_formatter = filters.empty? ? builder : Gherkin::Formatter::FilterFormatter.new(builder, filters)
32
+ tag_count_formatter = Gherkin::Formatter::TagCountFormatter.new(filter_formatter, tag_counts)
33
+ parser = Gherkin::Parser::Parser.new(tag_count_formatter, true, "root", false)
35
34
 
36
35
  begin
37
- s = ENV['FILTER_PML_CALLOUT'] ? source.gsub(C_CALLOUT, '') : source
38
- lexer.scan(s, @path, 0)
36
+ parser.parse(source, @path, 0)
39
37
  ast = builder.ast
40
38
  return nil if ast.nil? # Filter caused nothing to match
41
- ast.language = lexer.i18n_language
39
+ ast.language = parser.i18n_language
42
40
  ast.file = @path
43
41
  ast
44
42
  rescue Gherkin::LexingError, Gherkin::Parser::ParseError => e
@@ -125,17 +125,6 @@ module Cucumber
125
125
  end
126
126
  end
127
127
 
128
- def print_tag_limit_warnings(features)
129
- first_tag = true
130
- @options[:tag_excess].each do |tag_name, tag_limit, tag_locations|
131
- @io.puts if first_tag
132
- first_tag = false
133
- @io.puts format_string("#{tag_name} occurred #{tag_locations.length} times, but the limit was set to #{tag_limit}", :failed)
134
- tag_locations.each {|tag_location| @io.puts format_string(" #{tag_location.file_colon_line}", :failed)}
135
- @io.flush
136
- end
137
- end
138
-
139
128
  def embed(file, mime_type)
140
129
  # no-op
141
130
  end
@@ -69,7 +69,7 @@ module Cucumber
69
69
 
70
70
  def step_name(keyword, step_match, status, source_indent, background)
71
71
  @current_step[:status] = status
72
- @current_step[:keyword] = "#{keyword}"
72
+ @current_step[:keyword] = keyword
73
73
  @current_step[:name] = "#{step_match.name || step_match.format_args}"
74
74
  @current_step[:file_colon_line] = step_match.file_colon_line
75
75
  end
@@ -231,7 +231,6 @@ module Cucumber
231
231
  print_stats(features, @options.custom_profiles)
232
232
  print_snippets(@options)
233
233
  print_passing_wip(@options)
234
- print_tag_limit_warnings(features)
235
234
  end
236
235
  end
237
236
  end
@@ -68,7 +68,6 @@ module Cucumber
68
68
  print_stats(features, @options.custom_profiles)
69
69
  print_snippets(@options)
70
70
  print_passing_wip(@options)
71
- print_tag_limit_warnings(features)
72
71
  end
73
72
 
74
73
  CHARS = {
@@ -13,23 +13,23 @@ module Cucumber
13
13
  @feature || @multiline_arg
14
14
  end
15
15
 
16
- def feature(comments, tags, keyword, name, description, uri)
16
+ def feature(statement, uri)
17
17
  @feature = Ast::Feature.new(
18
18
  nil,
19
- Ast::Comment.new(comments.join("\n")),
20
- Ast::Tags.new(nil, tags),
21
- keyword,
22
- legacy_name_for(name, description),
19
+ Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
20
+ Ast::Tags.new(nil, statement.tags.map{|tag| tag.name}),
21
+ statement.keyword,
22
+ legacy_name_for(statement.name, statement.description),
23
23
  []
24
24
  )
25
25
  end
26
26
 
27
- def background(comments, keyword, name, description, line)
27
+ def background(statement)
28
28
  @background = Ast::Background.new(
29
- Ast::Comment.new(comments.join("\n")),
30
- line,
31
- keyword,
32
- legacy_name_for(name, description),
29
+ Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
30
+ statement.line,
31
+ statement.keyword,
32
+ legacy_name_for(statement.name, statement.description),
33
33
  steps=[]
34
34
  )
35
35
  @feature.background = @background
@@ -37,14 +37,14 @@ module Cucumber
37
37
  @step_container = @background
38
38
  end
39
39
 
40
- def scenario(comments, tags, keyword, name, description, line)
40
+ def scenario(statement)
41
41
  scenario = Ast::Scenario.new(
42
42
  @background,
43
- Ast::Comment.new(comments.join("\n")),
44
- Ast::Tags.new(nil, tags),
45
- line,
46
- keyword,
47
- legacy_name_for(name, description),
43
+ Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
44
+ Ast::Tags.new(nil, statement.tags.map{|tag| tag.name}),
45
+ statement.line,
46
+ statement.keyword,
47
+ legacy_name_for(statement.name, statement.description),
48
48
  steps=[]
49
49
  )
50
50
  @feature.add_feature_element(scenario)
@@ -52,14 +52,14 @@ module Cucumber
52
52
  @step_container = scenario
53
53
  end
54
54
 
55
- def scenario_outline(comments, tags, keyword, name, description, line)
55
+ def scenario_outline(statement)
56
56
  scenario_outline = Ast::ScenarioOutline.new(
57
57
  @background,
58
- Ast::Comment.new(comments.join("\n")),
59
- Ast::Tags.new(nil, tags),
60
- line,
61
- keyword,
62
- legacy_name_for(name, description),
58
+ Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
59
+ Ast::Tags.new(nil, statement.tags.map{|tag| tag.name}),
60
+ statement.line,
61
+ statement.keyword,
62
+ legacy_name_for(statement.name, statement.description),
63
63
  steps=[],
64
64
  example_sections=[]
65
65
  )
@@ -71,17 +71,23 @@ module Cucumber
71
71
  @step_container = scenario_outline
72
72
  end
73
73
 
74
- def examples(comments, tags, keyword, name, description, line, examples_table)
75
- examples_fields = [Ast::Comment.new(comments.join("\n")), line, keyword, legacy_name_for(name, description), matrix(examples_table)]
74
+ def examples(statement, examples_rows)
75
+ examples_fields = [
76
+ Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
77
+ statement.line,
78
+ statement.keyword,
79
+ legacy_name_for(statement.name, statement.description),
80
+ matrix(examples_rows)
81
+ ]
76
82
  @step_container.add_examples(examples_fields)
77
83
  end
78
84
 
79
- def step(comments, keyword, name, line, multiline_arg, status, exception, arguments, stepdef_location)
80
- @table_owner = Ast::Step.new(line, keyword, name)
85
+ def step(statement, multiline_arg, result)
86
+ @table_owner = Ast::Step.new(statement.line, statement.keyword, statement.name)
81
87
  multiline_arg = rubify(multiline_arg)
82
88
  case(multiline_arg)
83
- when String
84
- @table_owner.multiline_arg = Ast::PyString.new(multiline_arg)
89
+ when Gherkin::Formatter::Model::PyString
90
+ @table_owner.multiline_arg = Ast::PyString.new(multiline_arg.value)
85
91
  when Array
86
92
  @table_owner.multiline_arg = Ast::Table.new(matrix(multiline_arg))
87
93
  end
@@ -0,0 +1,16 @@
1
+ require 'rspec/core'
2
+
3
+ RSpec.configuration.configure_mock_framework
4
+ World(RSpec::Core::MockFrameworkAdapter)
5
+
6
+ Before do
7
+ _setup_mocks
8
+ end
9
+
10
+ After do
11
+ begin
12
+ _verify_mocks
13
+ ensure
14
+ _teardown_mocks
15
+ end
16
+ end
@@ -39,6 +39,12 @@ module Cucumber
39
39
  end
40
40
  end
41
41
 
42
+ class TagExcess < StandardError
43
+ def initialize(messages)
44
+ super(messages.join("\n"))
45
+ end
46
+ end
47
+
42
48
  # This is the meaty part of Cucumber that ties everything together.
43
49
  class StepMother
44
50
  include Constantize
@@ -55,11 +61,12 @@ module Cucumber
55
61
  def load_plain_text_features(feature_files)
56
62
  features = Ast::Features.new
57
63
 
64
+ tag_counts = {}
58
65
  start = Time.new
59
66
  log.debug("Features:\n")
60
67
  feature_files.each do |f|
61
68
  feature_file = FeatureFile.new(f)
62
- feature = feature_file.parse(self, options)
69
+ feature = feature_file.parse(options, tag_counts)
63
70
  if feature
64
71
  features.add_feature(feature)
65
72
  log.debug(" * #{f}\n")
@@ -67,9 +74,26 @@ module Cucumber
67
74
  end
68
75
  duration = Time.now - start
69
76
  log.debug("Parsing feature files took #{format_duration(duration)}\n\n")
77
+
78
+ check_tag_limits(tag_counts)
79
+
70
80
  features
71
81
  end
72
82
 
83
+ def check_tag_limits(tag_counts)
84
+ error_messages = []
85
+ options[:tag_expression].limits.each do |tag_name, tag_limit|
86
+ tag_locations = (tag_counts[tag_name] || [])
87
+ tag_count = tag_locations.length
88
+ if tag_count > tag_limit
89
+ error = "#{tag_name} occurred #{tag_count} times, but the limit was set to #{tag_limit}\n " +
90
+ tag_locations.join("\n ")
91
+ error_messages << error
92
+ end
93
+ end
94
+ raise TagExcess.new(error_messages) if error_messages.any?
95
+ end
96
+
73
97
  def load_code_files(step_def_files)
74
98
  log.debug("Code:\n")
75
99
  step_def_files.each do |step_def_file|
@@ -191,8 +215,8 @@ module Cucumber
191
215
  # })
192
216
  def invoke_steps(steps_text, i18n, file_colon_line)
193
217
  file, line = file_colon_line.split(':')
194
- lexer = i18n.lexer(Gherkin::Parser::Parser.new(StepInvoker.new(self), true, 'steps'))
195
- lexer.scan(steps_text, file, line.to_i)
218
+ parser = Gherkin::Parser::Parser.new(StepInvoker.new(self), true, 'steps')
219
+ parser.parse(steps_text, file, line.to_i)
196
220
  end
197
221
 
198
222
  class StepInvoker
@@ -200,37 +224,19 @@ module Cucumber
200
224
  @step_mother = step_mother
201
225
  end
202
226
 
203
- def location(uri, offset)
204
- end
205
-
206
- def step(keyword, name, line)
207
- invoke
208
- @name = name
209
- end
210
-
211
- def py_string(string, line)
212
- @multiline = Ast::PyString.new(string)
213
- end
214
-
215
- def row(row, line)
216
- @rows ||= []
217
- @rows << row
227
+ def step(statement, multiline_arg, result)
228
+ cucumber_multiline_arg = case(multiline_arg)
229
+ when Gherkin::Formatter::Model::PyString
230
+ multiline_arg.value
231
+ when Array
232
+ Ast::Table.new(multiline_arg.map{|row| row.cells})
233
+ else
234
+ nil
235
+ end
236
+ @step_mother.invoke(*[statement.name, cucumber_multiline_arg].compact)
218
237
  end
219
238
 
220
239
  def eof
221
- invoke
222
- end
223
-
224
- private
225
-
226
- def invoke
227
- if @name
228
- @multiline = Ast::Table.new(@rows) if @multiline.nil? && @rows
229
- @step_mother.invoke(*[@name, @multiline].compact)
230
- @name = nil
231
- @multiline = nil
232
- @rows = nil
233
- end
234
240
  end
235
241
  end
236
242