cucumber 0.8.7 → 0.9.0

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 (64) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +5 -0
  3. data/History.txt +16 -3
  4. data/Rakefile +4 -50
  5. data/cucumber.gemspec +36 -600
  6. data/features/cucumber_cli.feature +1 -1
  7. data/features/json_formatter.feature +1 -1
  8. data/features/junit_formatter.feature +10 -6
  9. data/features/post_configuration_hook.feature +15 -2
  10. data/features/step_definitions/cucumber_steps.rb +5 -1
  11. data/features/step_definitions/wire_steps.rb +1 -0
  12. data/features/support/env.rb +2 -5
  13. data/features/wire_protocol.feature +1 -1
  14. data/lib/cucumber.rb +8 -0
  15. data/lib/cucumber/ast/outline_table.rb +4 -4
  16. data/lib/cucumber/ast/step_invocation.rb +14 -13
  17. data/lib/cucumber/ast/table.rb +2 -1
  18. data/lib/cucumber/ast/tree_walker.rb +3 -3
  19. data/lib/cucumber/cli/configuration.rb +32 -7
  20. data/lib/cucumber/cli/main.rb +26 -30
  21. data/lib/cucumber/cli/options.rb +1 -3
  22. data/lib/cucumber/cli/profile_loader.rb +2 -0
  23. data/lib/cucumber/configuration.rb +37 -0
  24. data/lib/cucumber/errors.rb +40 -0
  25. data/lib/cucumber/feature_file.rb +5 -12
  26. data/lib/cucumber/formatter/junit.rb +2 -2
  27. data/lib/cucumber/formatter/tag_cloud.rb +1 -1
  28. data/lib/cucumber/js_support/js_dsl.js +4 -4
  29. data/lib/cucumber/js_support/js_language.rb +9 -5
  30. data/lib/cucumber/language_support.rb +2 -2
  31. data/lib/cucumber/parser/gherkin_builder.rb +19 -19
  32. data/lib/cucumber/platform.rb +3 -4
  33. data/lib/cucumber/rake/task.rb +1 -7
  34. data/lib/cucumber/rb_support/rb_dsl.rb +1 -0
  35. data/lib/cucumber/rb_support/rb_language.rb +1 -0
  36. data/lib/cucumber/rspec/doubles.rb +3 -3
  37. data/lib/cucumber/runtime.rb +192 -0
  38. data/lib/cucumber/runtime/features_loader.rb +62 -0
  39. data/lib/cucumber/runtime/results.rb +46 -0
  40. data/lib/cucumber/runtime/support_code.rb +174 -0
  41. data/lib/cucumber/runtime/user_interface.rb +80 -0
  42. data/lib/cucumber/step_mother.rb +6 -427
  43. data/lib/cucumber/wire_support/configuration.rb +2 -0
  44. data/lib/cucumber/wire_support/wire_language.rb +1 -8
  45. data/spec/cucumber/ast/background_spec.rb +3 -3
  46. data/spec/cucumber/ast/feature_spec.rb +2 -2
  47. data/spec/cucumber/ast/scenario_outline_spec.rb +1 -1
  48. data/spec/cucumber/ast/scenario_spec.rb +1 -2
  49. data/spec/cucumber/ast/tree_walker_spec.rb +1 -1
  50. data/spec/cucumber/cli/configuration_spec.rb +31 -5
  51. data/spec/cucumber/cli/drb_client_spec.rb +1 -1
  52. data/spec/cucumber/cli/main_spec.rb +8 -37
  53. data/spec/cucumber/cli/options_spec.rb +20 -0
  54. data/spec/cucumber/formatter/spec_helper.rb +5 -7
  55. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  56. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
  57. data/spec/cucumber/runtime_spec.rb +294 -0
  58. data/spec/cucumber/step_match_spec.rb +10 -8
  59. data/spec/cucumber/world/pending_spec.rb +1 -1
  60. data/spec/spec_helper.rb +2 -21
  61. metadata +215 -84
  62. data/Caliper.yml +0 -4
  63. data/VERSION.yml +0 -5
  64. data/spec/cucumber/step_mother_spec.rb +0 -302
@@ -337,7 +337,7 @@ Feature: Cucumber command line
337
337
  """
338
338
 
339
339
  Scenario: Multiple formatters and outputs
340
- When I run cucumber --format progress --out tmp/progress.txt --format pretty --out tmp/pretty.txt --no-source --dry-run features/lots_of_undefined.feature
340
+ When I run cucumber --format progress --out tmp/progress.txt --format pretty --out tmp/pretty.txt --no-source --dry-run --no-snippets features/lots_of_undefined.feature
341
341
  Then STDERR should be empty
342
342
  Then "fixtures/self_test/tmp/progress.txt" should contain
343
343
  """
@@ -176,7 +176,7 @@ Feature: JSON output formatter
176
176
  ],
177
177
  "exception": {
178
178
  "class": "RSpec::Expectations::ExpectationNotMetError",
179
- "message": "expected: 4,\n got: 5 (using ==)\nDiff:\n@@ -1,2 +1,2 @@\n-4\n+5\n",
179
+ "message": "expected: 4,\n got: 5 (using ==)",
180
180
  "backtrace": [
181
181
  "./features/step_definitions/steps.rb:18:in `/^I the result should be (\\d+)$/'",
182
182
  "features/tables.feature:8:in `Then I the result should be <c>'"
@@ -20,13 +20,15 @@ Feature: JUnit output formatter
20
20
  </testcase>
21
21
  <testcase classname="One passing scenario, one failing scenario.Failing" name="Failing" time="0.005">
22
22
  <failure message="failed Failing" type="failed">
23
- Scenario: Failing
23
+ <![CDATA[Scenario: Failing
24
24
 
25
25
  Given a failing scenario
26
26
 
27
27
  Message:
28
- (RuntimeError)
29
- features/one_passing_one_failing.feature:7:in `Given a failing scenario' </failure>
28
+ ]]>
29
+ <![CDATA[ (RuntimeError)
30
+ features/one_passing_one_failing.feature:7:in `Given a failing scenario']]>
31
+ </failure>
30
32
  </testcase>
31
33
  </testsuite>
32
34
 
@@ -58,10 +60,12 @@ Feature: JUnit output formatter
58
60
  <testsuite errors="0" failures="1" name="Pending step" tests="1" time="0.000160">
59
61
  <testcase classname="Pending step.Pending" name="Pending" time="0.000160">
60
62
  <failure message="pending Pending" type="pending">
61
- Scenario: Pending
63
+ <![CDATA[Scenario: Pending
62
64
 
63
- TODO (Cucumber::Pending)
64
- features/pending.feature:4:in `Given a pending step' </failure>
65
+ ]]>
66
+ <![CDATA[TODO (Cucumber::Pending)
67
+ features/pending.feature:4:in `Given a pending step']]>
68
+ </failure>
65
69
  </testcase>
66
70
  </testsuite>
67
71
 
@@ -4,13 +4,26 @@ Feature: Post Configuration Hook [#423]
4
4
  As a developer
5
5
  I want to manipulate the Cucumber configuration after it has been created
6
6
 
7
- Scenario: configuration modified to use HTML formatter
7
+ Scenario: Using options directly gets a deprecation warning
8
8
 
9
9
  Given a standard Cucumber project directory structure
10
10
  And a file named "features/support/env.rb" with:
11
11
  """
12
12
  AfterConfiguration do |config|
13
- config.options[:formats] << ['html', config.out_stream]
13
+ config.options[:blah]
14
+ end
15
+ """
16
+ When I run cucumber features
17
+ Then STDERR should match
18
+ """
19
+ Deprecated
20
+ """
21
+
22
+ Given a standard Cucumber project directory structure
23
+ And a file named "features/support/env.rb" with:
24
+ """
25
+ AfterConfiguration do |config|
26
+ config.formats << ['html', config.out_stream]
14
27
  end
15
28
  """
16
29
  When I run cucumber features
@@ -50,7 +50,11 @@ Given /^I have environment variable (\w+) set to "([^"]*)"$/ do |variable, value
50
50
  end
51
51
 
52
52
  When /^I run cucumber (.*)$/ do |cucumber_opts|
53
- run "#{Cucumber::RUBY_BINARY} -r rubygems #{Cucumber::BINARY} --no-color #{cucumber_opts} CUCUMBER_OUTPUT_ENCODING=UTF-8"
53
+ # Don't use Cucumber::BINARY (which is the binary used to start the "outer" cucumber)
54
+ # Instead we force the use of this codebase's cucumber bin script.
55
+ # This allows us to run cucumber's cukes with an older, stable cucumber.
56
+ cucumber_bin = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
57
+ run "#{Cucumber::RUBY_BINARY} -I rubygems #{cucumber_bin} --no-color #{cucumber_opts} CUCUMBER_OUTPUT_ENCODING=UTF-8"
54
58
  end
55
59
 
56
60
  When /^I run rake (.*)$/ do |rake_opts|
@@ -12,6 +12,7 @@ end
12
12
  module WireHelper
13
13
  def start_wire_server
14
14
  @wire_pid = fork do
15
+ at_exit { stop_wire_server }
15
16
  @server.run
16
17
  end
17
18
  end
@@ -1,10 +1,7 @@
1
1
  require 'rubygems'
2
+
2
3
  require 'tempfile'
3
- begin
4
- require 'rspec/expectations'
5
- rescue LoadError
6
- require 'spec/expectations'
7
- end
4
+ require 'rspec/expectations'
8
5
  require 'fileutils'
9
6
  require 'forwardable'
10
7
  require 'cucumber/formatter/unicode'
@@ -67,7 +67,7 @@ Feature: Wire Protocol
67
67
  Given there is a wire server running on port 54321 which understands the following protocol:
68
68
  | request | response |
69
69
  | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
70
- When I run cucumber --dry-run -f progress
70
+ When I run cucumber --dry-run --no-snippets -f progress
71
71
  And it should pass with
72
72
  """
73
73
  U
@@ -11,5 +11,13 @@ require 'cucumber/broadcaster'
11
11
  module Cucumber
12
12
  class << self
13
13
  attr_accessor :wants_to_quit
14
+
15
+ def logger
16
+ @log ||= Logger.new(STDOUT)
17
+ end
18
+
19
+ def logger=(logger)
20
+ @log = logger
21
+ end
14
22
  end
15
23
  end
@@ -21,7 +21,7 @@ module Cucumber
21
21
  return if Cucumber.wants_to_quit
22
22
  init
23
23
  cells_rows.each_with_index do |row, n|
24
- if(visitor.options[:expand])
24
+ if(visitor.configuration.expand?)
25
25
  row.accept(visitor)
26
26
  else
27
27
  visitor.visit_table_row(row)
@@ -96,7 +96,7 @@ module Cucumber
96
96
 
97
97
  def accept(visitor)
98
98
  return if Cucumber.wants_to_quit
99
- visitor.options[:expand] ? accept_expand(visitor) : accept_plain(visitor)
99
+ visitor.configuration.expand? ? accept_expand(visitor) : accept_plain(visitor)
100
100
  end
101
101
 
102
102
  def accept_plain(visitor)
@@ -108,7 +108,7 @@ module Cucumber
108
108
  else
109
109
  visitor.step_mother.with_hooks(self) do
110
110
  @step_invocations.each do |step_invocation|
111
- step_invocation.invoke(visitor.step_mother, visitor.options)
111
+ step_invocation.invoke(visitor.step_mother, visitor.configuration)
112
112
  @exception ||= step_invocation.reported_exception
113
113
  end
114
114
 
@@ -127,7 +127,7 @@ module Cucumber
127
127
  visitor.step_mother.with_hooks(self) do
128
128
  @table.visit_scenario_name(visitor, self)
129
129
  @step_invocations.each do |step_invocation|
130
- step_invocation.invoke(visitor.step_mother, visitor.options)
130
+ step_invocation.invoke(visitor.step_mother, visitor.configuration)
131
131
  @exception ||= step_invocation.reported_exception
132
132
  step_invocation.visit_step_result(visitor)
133
133
  end
@@ -1,3 +1,4 @@
1
+ require 'cucumber/errors'
1
2
  require 'cucumber/step_match'
2
3
  require 'cucumber/ast/table'
3
4
  require 'gherkin/rubify'
@@ -38,7 +39,7 @@ module Cucumber
38
39
 
39
40
  def accept(visitor)
40
41
  return if Cucumber.wants_to_quit
41
- invoke(visitor.step_mother, visitor.options)
42
+ invoke(visitor.step_mother, visitor.configuration)
42
43
  visit_step_result(visitor)
43
44
  end
44
45
 
@@ -54,53 +55,53 @@ module Cucumber
54
55
  )
55
56
  end
56
57
 
57
- def invoke(step_mother, options)
58
- find_step_match!(step_mother)
59
- unless @skip_invoke || options[:dry_run] || @exception || @step_collection.exception
58
+ def invoke(step_mother, configuration)
59
+ find_step_match!(step_mother, configuration)
60
+ unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
60
61
  @skip_invoke = true
61
62
  begin
62
63
  @step_match.invoke(@multiline_arg)
63
64
  step_mother.after_step
64
65
  status!(:passed)
65
66
  rescue Pending => e
66
- failed(options, e, false)
67
+ failed(configuration, e, false)
67
68
  status!(:pending)
68
69
  rescue Undefined => e
69
- failed(options, e, false)
70
+ failed(configuration, e, false)
70
71
  status!(:undefined)
71
72
  rescue Cucumber::Ast::Table::Different => e
72
73
  @different_table = e.table
73
- failed(options, e, false)
74
+ failed(configuration, e, false)
74
75
  status!(:failed)
75
76
  rescue Exception => e
76
- failed(options, e, false)
77
+ failed(configuration, e, false)
77
78
  status!(:failed)
78
79
  end
79
80
  end
80
81
  end
81
82
 
82
- def find_step_match!(step_mother)
83
+ def find_step_match!(step_mother, configuration)
83
84
  return if @step_match
84
85
  begin
85
86
  @step_match = step_mother.step_match(@name)
86
87
  rescue Undefined => e
87
- failed(step_mother.options, e, true)
88
+ failed(configuration, e, true)
88
89
  status!(:undefined)
89
90
  @step_match = NoStepMatch.new(@step, @name)
90
91
  rescue Ambiguous => e
91
- failed(step_mother.options, e, false)
92
+ failed(configuration, e, false)
92
93
  status!(:failed)
93
94
  @step_match = NoStepMatch.new(@step, @name)
94
95
  end
95
96
  step_mother.step_visited(self)
96
97
  end
97
98
 
98
- def failed(options, e, clear_backtrace)
99
+ def failed(configuration, e, clear_backtrace)
99
100
  e = filter_backtrace(e)
100
101
  e.set_backtrace([]) if clear_backtrace
101
102
  e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
102
103
  @exception = e
103
- if(options[:strict] || !(Undefined === e) || e.nested?)
104
+ if(configuration.strict? || !(Undefined === e) || e.nested?)
104
105
  @reported_exception = e
105
106
  else
106
107
  @reported_exception = nil
@@ -1,4 +1,5 @@
1
1
  require 'gherkin/rubify'
2
+ require 'gherkin/lexer/i18n_lexer'
2
3
  require 'gherkin/formatter/escaping'
3
4
 
4
5
  module Cucumber
@@ -60,7 +61,7 @@ module Cucumber
60
61
 
61
62
  def self.parse(text, uri, offset)
62
63
  builder = Builder.new
63
- lexer = Gherkin::I18nLexer.new(builder)
64
+ lexer = Gherkin::Lexer::I18nLexer.new(builder)
64
65
  lexer.scan(text)
65
66
  new(builder.rows)
66
67
  end
@@ -2,11 +2,11 @@ module Cucumber
2
2
  module Ast
3
3
  # Walks the AST, executing steps and notifying listeners
4
4
  class TreeWalker
5
- attr_accessor :options #:nodoc:
5
+ attr_accessor :configuration #:nodoc:
6
6
  attr_reader :step_mother #:nodoc:
7
7
 
8
- def initialize(step_mother, listeners = [], options = {}, io = STDOUT)
9
- @step_mother, @listeners, @options, @io = step_mother, listeners, options, io
8
+ def initialize(step_mother, listeners = [], configuration = Cucumber::Configuration.default)
9
+ @step_mother, @listeners, @configuration = step_mother, listeners, configuration
10
10
  end
11
11
 
12
12
  def visit_features(features)
@@ -12,7 +12,7 @@ module Cucumber
12
12
  class Configuration
13
13
  include Constantize
14
14
 
15
- attr_reader :options, :out_stream
15
+ attr_reader :out_stream
16
16
 
17
17
  def initialize(out_stream = STDOUT, error_stream = STDERR)
18
18
  @out_stream = out_stream
@@ -56,8 +56,16 @@ module Cucumber
56
56
  @options[:drb_port].to_i if @options[:drb_port]
57
57
  end
58
58
 
59
- def build_runner(step_mother, io)
60
- Ast::TreeWalker.new(step_mother, formatters(step_mother), @options, io)
59
+ def dry_run?
60
+ @options[:dry_run]
61
+ end
62
+
63
+ def expand?
64
+ @options[:expand]
65
+ end
66
+
67
+ def build_tree_walker(step_mother)
68
+ Ast::TreeWalker.new(step_mother, formatters(step_mother), self)
61
69
  end
62
70
 
63
71
  def formatter_class(format)
@@ -121,7 +129,27 @@ module Cucumber
121
129
  logger.level = Logger::DEBUG if self.verbose?
122
130
  logger
123
131
  end
124
-
132
+
133
+ def tag_expression
134
+ Gherkin::TagExpression.new(@options[:tag_expressions])
135
+ end
136
+
137
+ def filters
138
+ @options.filters
139
+ end
140
+
141
+ def formats
142
+ @options[:formats]
143
+ end
144
+
145
+ def options
146
+ warn("Deprecated: Configuration#options will be removed from the next release of Cucumber. Please use the configuration object directly instead.")
147
+ @options
148
+ end
149
+
150
+ def paths
151
+ @options[:paths].empty? ? ['features'] : @options[:paths]
152
+ end
125
153
  private
126
154
 
127
155
  def formatters(step_mother)
@@ -151,9 +179,6 @@ module Cucumber
151
179
  end
152
180
  end
153
181
 
154
- def paths
155
- @options[:paths].empty? ? ['features'] : @options[:paths]
156
- end
157
182
 
158
183
  def set_environment_variables
159
184
  @options[:env_vars].each do |var, value|
@@ -13,16 +13,20 @@ require 'cucumber/formatter/color_io'
13
13
  require 'cucumber/cli/configuration'
14
14
  require 'cucumber/cli/drb_client'
15
15
 
16
+ if defined?(Spork::TestFramework::Cucumber)
17
+ class Spork::TestFramework::Cucumber < Spork::TestFramework
18
+ def run_tests(argv, stderr, stdout)
19
+ ::Cucumber::Cli::Main.new(argv, stdout, stderr).execute!
20
+ end
21
+ end
22
+ end
23
+
16
24
  module Cucumber
17
25
  module Cli
18
26
  class Main
19
27
  class << self
20
- def step_mother
21
- @step_mother ||= StepMother.new
22
- end
23
-
24
28
  def execute(args)
25
- new(args).execute!(step_mother)
29
+ new(args).execute!
26
30
  end
27
31
  end
28
32
 
@@ -38,34 +42,17 @@ module Cucumber
38
42
  @configuration = nil
39
43
  end
40
44
 
41
- def execute!(step_mother)
42
- trap_interrupt
43
- if configuration.drb?
44
- begin
45
- return DRbClient.run(@args, @error_stream, @out_stream, configuration.drb_port)
46
- rescue DRbClientError => e
47
- @error_stream.puts "WARNING: #{e.message} Running features locally:"
48
- end
45
+ def execute!(legacy_step_mother = nil)
46
+ if legacy_step_mother
47
+ warn("Passing a step_mother to #execute! is deprecated, and has been ignored: #{caller[0]}")
49
48
  end
50
- step_mother.options = configuration.options
51
- step_mother.log = configuration.log
52
49
 
53
- step_mother.load_code_files(configuration.support_to_load)
54
- step_mother.after_configuration(configuration)
55
- features = step_mother.load_plain_text_features(configuration.feature_files)
56
- step_mother.load_code_files(configuration.step_defs_to_load)
57
-
58
- runner = configuration.build_runner(step_mother, @out_stream)
59
- step_mother.visitor = runner # Needed to support World#announce
50
+ trap_interrupt
51
+ return @drb_output if run_drb_client
60
52
 
61
- runner.visit_features(features)
62
-
63
- failure = if configuration.wip?
64
- step_mother.scenarios(:passed).any?
65
- else
66
- step_mother.scenarios(:failed).any? ||
67
- (configuration.strict? && (step_mother.steps(:undefined).any? || step_mother.steps(:pending).any?))
68
- end
53
+ runtime = Runtime.new(configuration)
54
+ runtime.run!
55
+ runtime.results.failure?
69
56
  rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
70
57
  @error_stream.puts e.message
71
58
  true
@@ -76,10 +63,19 @@ module Cucumber
76
63
 
77
64
  @configuration = Configuration.new(@out_stream, @error_stream)
78
65
  @configuration.parse!(@args)
66
+ Cucumber.logger = @configuration.log
79
67
  @configuration
80
68
  end
81
69
 
82
70
  private
71
+
72
+ def run_drb_client
73
+ return false unless configuration.drb?
74
+ @drb_output = DRbClient.run(@args, @error_stream, @out_stream, configuration.drb_port)
75
+ true
76
+ rescue DRbClientError => e
77
+ @error_stream.puts "WARNING: #{e.message} Running features locally:"
78
+ end
83
79
 
84
80
  def trap_interrupt
85
81
  trap('INT') do
@@ -199,10 +199,8 @@ module Cucumber
199
199
  Term::ANSIColor.coloring = v
200
200
  end
201
201
  opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
202
- "This also omits the loading of your support/env.rb file if it exists.",
203
- "Implies --no-snippets.") do
202
+ "This also omits the loading of your support/env.rb file if it exists.") do
204
203
  @options[:dry_run] = true
205
- @options[:snippets] = false
206
204
  end
207
205
  opts.on("-a", "--autoformat DIR",
208
206
  "Reformats (pretty prints) feature files and write them to DIRECTORY.",