cucumber 0.8.7 → 0.9.0

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