cucumber 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
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