cucumber 0.3.98 → 0.3.99

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.3.99 2009-09-03
2
+
3
+ === New Features
4
+ * Support for Croatian (Bkrsta)
5
+ * Make #feature available from scenario so you can do: Before{|scenario| scenario.feature}. (Aslak Hellesøy)
6
+ * cucumber.yml parsing supports ERB syntax (#427 Gregory Hnatiuk)
7
+ * New AfterConfiguration hook added; a block can be specified that takes Cucumber::Cli::Configuration (#423 Brent Snook)
8
+ * Cucumber::Cli::Configuration#feature_dirs and #out_stream exposed as public attributes so that they may be used in AfterConfiguration hook (#423 Brent Snook)
9
+
1
10
  == 0.3.98 2009-08-25
2
11
 
3
12
  Just a small release to help Cuke4Duke, which will be presented at Agile2009
data/Manifest.txt CHANGED
@@ -269,6 +269,7 @@ features/html_formatter/a.html
269
269
  features/junit_formatter.feature
270
270
  features/language_from_header.feature
271
271
  features/multiline_names.feature
272
+ features/post_configuration_hook.feature
272
273
  features/profiles.feature
273
274
  features/rake_task.feature
274
275
  features/report_called_undefined_steps.feature
@@ -0,0 +1,37 @@
1
+ Feature: Post Configuration Hook [#423]
2
+
3
+ In order to extend Cucumber
4
+ As a developer
5
+ I want to manipulate the Cucumber configuration after it has been created
6
+
7
+ Scenario: configuration modified to use HTML formatter
8
+
9
+ Given a standard Cucumber project directory structure
10
+ And a file named "features/support/env.rb" with:
11
+ """
12
+ AfterConfiguration do |config|
13
+ config.options[:formats] << ['html', config.out_stream]
14
+ end
15
+ """
16
+ When I run cucumber features
17
+ Then STDERR should be empty
18
+ And the output should contain
19
+ """
20
+ html
21
+ """
22
+
23
+ Scenario: feature directories read from configuration
24
+
25
+ Given a standard Cucumber project directory structure
26
+ And a file named "features/support/env.rb" with:
27
+ """
28
+ AfterConfiguration do |config|
29
+ config.out_stream << "AfterConfiguration hook read feature directories: #{config.feature_dirs}"
30
+ end
31
+ """
32
+ When I run cucumber features
33
+ Then STDERR should be empty
34
+ And the output should contain
35
+ """
36
+ AfterConfiguration hook read feature directories: features
37
+ """
@@ -30,6 +30,19 @@ Feature: Profiles
30
30
  """
31
31
  And exactly these files should be loaded: features/support/super_env.rb
32
32
 
33
+ Scenario: Explicitly defining a profile defined in an ERB formatted file
34
+ Given the following profiles are defined:
35
+ """
36
+ <% requires = "--require features/support/super_env.rb" %>
37
+ super: <%= "features/sample.feature #{requires} -v" %>
38
+ """
39
+ When I run cucumber features/sample.feature --profile super
40
+ Then the output should contain
41
+ """
42
+ Using the super profile...
43
+ """
44
+ And exactly these files should be loaded: features/support/super_env.rb
45
+
33
46
  Scenario: Defining multiple profiles to run
34
47
  When I run cucumber features/sample.feature --profile default --profile super
35
48
  Then the output should contain
@@ -96,7 +96,7 @@ module Autotest::CucumberMixin
96
96
  $stdout.sync = old_sync
97
97
  end
98
98
  self.features_to_run = dirty_features_file.read.strip
99
- self.tainted = true unless self.features_to_run == []
99
+ self.tainted = true unless self.features_to_run == ''
100
100
  end
101
101
  hook :ran_features
102
102
  end
@@ -122,4 +122,4 @@ module Autotest::CucumberMixin
122
122
 
123
123
  return "#{Cucumber::RUBY_BINARY} #{Cucumber::BINARY} #{args}"
124
124
  end
125
- end
125
+ end
@@ -2,7 +2,7 @@ require 'enumerator'
2
2
 
3
3
  module Cucumber
4
4
  module FeatureElement #:nodoc:
5
- attr_writer :feature
5
+ attr_accessor :feature
6
6
 
7
7
  def attach_steps(steps)
8
8
  steps.each {|step| step.feature_element = self}
@@ -10,7 +10,7 @@ module Cucumber
10
10
  class Configuration
11
11
  include Constantize
12
12
 
13
- attr_reader :options
13
+ attr_reader :options, :out_stream
14
14
 
15
15
  def initialize(out_stream = STDOUT, error_stream = STDERR)
16
16
  @out_stream = out_stream
@@ -94,21 +94,29 @@ module Cucumber
94
94
  end
95
95
  end
96
96
 
97
- def step_defs_to_load
97
+ def all_files_to_load
98
98
  requires = @options[:require].empty? ? require_dirs : @options[:require]
99
99
  files = requires.map do |path|
100
100
  path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
101
101
  path = path.gsub(/\/$/, '') # Strip trailing slash.
102
102
  File.directory?(path) ? Dir["#{path}/**/*"] : path
103
103
  end.flatten.uniq
104
- sorted_files = files.sort { |a,b| (b =~ %r{/support/} || -1) <=> (a =~ %r{/support/} || -1) }.reject{|f| f =~ /^http/}
105
- env_files = sorted_files.select {|f| f =~ %r{/support/env\..*} }
106
- files = env_files + sorted_files.reject {|f| f =~ %r{/support/env\..*} }
107
104
  remove_excluded_files_from(files)
108
105
  files.reject! {|f| !File.file?(f)}
109
106
  files.reject! {|f| File.extname(f) == '.feature' }
110
- files.reject! {|f| f =~ %r{/support/env\..*} } if @options[:dry_run]
111
- files
107
+ files.reject! {|f| f =~ /^http/}
108
+ files
109
+ end
110
+
111
+ def step_defs_to_load
112
+ all_files_to_load.reject {|f| f =~ %r{/support/} }
113
+ end
114
+
115
+ def support_to_load
116
+ support_files = all_files_to_load.select {|f| f =~ %r{/support/} }
117
+ env_files = support_files.select {|f| f =~ %r{/support/env\..*} }
118
+ other_files = support_files - env_files
119
+ @options[:dry_run] ? other_files : env_files + other_files
112
120
  end
113
121
 
114
122
  def feature_files
@@ -120,6 +128,10 @@ module Cucumber
120
128
  remove_excluded_files_from(potential_feature_files)
121
129
  potential_feature_files
122
130
  end
131
+
132
+ def feature_dirs
133
+ paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
134
+ end
123
135
 
124
136
  private
125
137
 
@@ -136,8 +148,9 @@ module Cucumber
136
148
  def arrange_formats
137
149
  @options[:formats] << ['pretty', @out_stream] if @options[:formats].empty?
138
150
  @options[:formats] = @options[:formats].sort_by{|f| f[1] == @out_stream ? -1 : 1}
139
- if @options[:formats].length > 1 && @options[:formats][1][1] == @out_stream
140
- raise "All but one formatter must use --out, only one can print to STDOUT"
151
+ streams = @options[:formats].map { |(_, stream)| stream }
152
+ if streams != streams.uniq
153
+ raise "All but one formatter must use --out, only one can print to each stream (or STDOUT)"
141
154
  end
142
155
  end
143
156
 
@@ -145,10 +158,6 @@ module Cucumber
145
158
  files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
146
159
  end
147
160
 
148
- def feature_dirs
149
- paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
150
- end
151
-
152
161
  def require_dirs
153
162
  feature_dirs + Dir['vendor/{gems,plugins}/*/cucumber']
154
163
  end
@@ -53,10 +53,8 @@ module Cucumber
53
53
  logger.level = Logger::DEBUG if configuration.verbose?
54
54
  step_mother.log = logger
55
55
 
56
- # Feature files must be loaded before files are required.
57
- # This is because i18n step methods are only aliased when
58
- # features are loaded. If we swap the order, the requires
59
- # will fail.
56
+ step_mother.load_code_files(configuration.support_to_load)
57
+ step_mother.after_configuration(configuration)
60
58
  features = step_mother.load_plain_text_features(configuration.feature_files)
61
59
  step_mother.load_code_files(configuration.step_defs_to_load)
62
60
  enable_diffing
@@ -43,9 +43,16 @@ Defined profiles in cucumber.yml:
43
43
  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")
44
44
  end
45
45
 
46
+ require 'erb'
46
47
  require 'yaml'
48
+ begin
49
+ @cucumber_erb = ERB.new(IO.read('cucumber.yml')).result
50
+ rescue Exception => e
51
+ raise(YmlLoadError,"cucumber.yml was found, but could not be parsed with ERB. Please refer to cucumber's documentation on correct profile usage.\n#{$!.inspect}")
52
+ end
53
+
47
54
  begin
48
- @cucumber_yml = YAML::load(IO.read('cucumber.yml'))
55
+ @cucumber_yml = YAML::load(@cucumber_erb)
49
56
  rescue StandardError => e
50
57
  raise(YmlLoadError,"cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentation on correct profile usage.\n")
51
58
  end
@@ -10,6 +10,12 @@ module Cucumber
10
10
  execute_after(scenario)
11
11
  end_scenario
12
12
  end
13
+
14
+ def after_configuration(configuration)
15
+ hooks[:after_configuration].each do |hook|
16
+ hook.invoke('AfterConfiguration', configuration)
17
+ end
18
+ end
13
19
 
14
20
  def execute_after_step(scenario)
15
21
  hooks_for(:after_step, scenario).each do |hook|
@@ -1,3 +1,5 @@
1
+ require 'cucumber/core_ext/string'
2
+
1
3
  module Cucumber
2
4
  module LanguageSupport
3
5
  module StepDefinitionMethods
@@ -251,6 +251,21 @@
251
251
  and: וגם
252
252
  but: אבל
253
253
  space_after_keyword: true
254
+ "hr":
255
+ name: Croatian
256
+ native: hrvatski
257
+ encoding: UTF-8
258
+ feature: Osobina|Mogućnost|Mogucnost
259
+ background: Pozadina
260
+ scenario: Scenarij
261
+ scenario_outline: Skica|Koncept
262
+ examples: Primjeri|Scenariji
263
+ given: Zadan|Zadani|Zadano
264
+ when: Kada|Kad
265
+ then: Onda
266
+ and: I
267
+ but: Ali
268
+ space_after_keyword: true
254
269
  "hu":
255
270
  name: Hungarian
256
271
  native: magyar
@@ -65,6 +65,12 @@ module Cucumber
65
65
  def AfterStep(*tag_names, &proc)
66
66
  RbDsl.register_rb_hook('after_step', tag_names, proc)
67
67
  end
68
+
69
+ # Registers a proc that will run after Cucumber is configured. You can register as
70
+ # as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
71
+ def AfterConfiguration(&proc)
72
+ RbDsl.register_rb_hook('after_configuration', [], proc)
73
+ end
68
74
 
69
75
  # Registers a new Ruby StepDefinition. This method is aliased
70
76
  # to <tt>Given</tt>, <tt>When</tt> and <tt>Then</tt>, and
@@ -10,8 +10,8 @@ module Cucumber
10
10
  @proc = proc
11
11
  end
12
12
 
13
- def invoke(location, scenario)
14
- @rb_language.current_world.cucumber_instance_exec(false, location, scenario, &@proc)
13
+ def invoke(location, argument)
14
+ @rb_language.current_world.cucumber_instance_exec(false, location, argument, &@proc)
15
15
  end
16
16
  end
17
17
  end
@@ -233,6 +233,12 @@ module Cucumber
233
233
  end
234
234
  end
235
235
 
236
+ def after_configuration(configuration) #:nodoc
237
+ @programming_languages.each do |programming_language|
238
+ programming_language.after_configuration(configuration)
239
+ end
240
+ end
241
+
236
242
  private
237
243
 
238
244
  # Registers a StepDefinition. This can be a Ruby StepDefintion,
@@ -2,7 +2,7 @@ module Cucumber #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
- TINY = 98
5
+ TINY = 99
6
6
  PATCH = nil # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
@@ -7,12 +7,12 @@ begin
7
7
  namespace :cucumber do
8
8
  Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
9
9
  t.fork = true # You may get faster startup if you set this to false
10
- t.cucumber_opts = "--tags ~@wip --strict --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}<%= spork? ? ' --drb' : '' %>"
10
+ t.cucumber_opts = "--color --tags ~@wip --strict --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}<%= spork? ? ' --drb' : '' %>"
11
11
  end
12
12
 
13
13
  Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
14
14
  t.fork = true # You may get faster startup if you set this to false
15
- t.cucumber_opts = "--tags @wip:2 --wip --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}<%= spork? ? ' --drb' : '' %>"
15
+ t.cucumber_opts = "--color --tags @wip:2 --wip --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}<%= spork? ? ' --drb' : '' %>"
16
16
  end
17
17
 
18
18
  desc 'Run all features'
@@ -18,7 +18,6 @@ module Cli
18
18
  end
19
19
 
20
20
  before(:each) do
21
- #given_cucumber_yml_defined_as({'default' => '-q'})
22
21
  File.stub!(:exist?).and_return(false) # Meaning, no cucumber.yml exists
23
22
  Kernel.stub!(:exit).and_return(nil)
24
23
  end
@@ -33,24 +32,12 @@ module Cli
33
32
 
34
33
  attr_reader :out, :error
35
34
 
36
-
37
- it "should require files in support paths first" do
38
- given_the_following_files("/features/step_definitions/foo.rb","/features/support/bar.rb")
39
-
40
- config.parse!(%w{--require /features})
41
-
42
- config.step_defs_to_load.should == [
43
- "/features/support/bar.rb",
44
- "/features/step_definitions/foo.rb"
45
- ]
46
- end
47
-
48
35
  it "should require env.rb files first" do
49
36
  given_the_following_files("/features/support/a_file.rb","/features/support/env.rb")
50
37
 
51
38
  config.parse!(%w{--require /features})
52
39
 
53
- config.step_defs_to_load.should == [
40
+ config.support_to_load.should == [
54
41
  "/features/support/env.rb",
55
42
  "/features/support/a_file.rb"
56
43
  ]
@@ -61,7 +48,7 @@ module Cli
61
48
 
62
49
  config.parse!(%w{--require /features --dry-run})
63
50
 
64
- config.step_defs_to_load.should == [
51
+ config.support_to_load.should == [
65
52
  "/features/support/a_file.rb"
66
53
  ]
67
54
  end
@@ -85,7 +72,7 @@ module Cli
85
72
 
86
73
  config.parse!(%w{--require /features --exclude a_file.rb})
87
74
 
88
- config.step_defs_to_load.should == [
75
+ config.all_files_to_load.should == [
89
76
  "/features/support/env.rb"
90
77
  ]
91
78
  end
@@ -97,7 +84,7 @@ module Cli
97
84
 
98
85
  config.parse!(%w{--require /features --exclude foo[df] --exclude blah})
99
86
 
100
- config.step_defs_to_load.should == [
87
+ config.all_files_to_load.should == [
101
88
  "/features/support/bar.rb",
102
89
  "/features/support/fooz.rb"
103
90
  ]
@@ -152,6 +139,13 @@ module Cli
152
139
  config.parse!([])
153
140
  config.options[:require].should == ['from/yml']
154
141
  end
142
+
143
+ it "parses ERB syntax in the cucumber.yml file" do
144
+ given_cucumber_yml_defined_as({'default' => '<%="--require some_file"%>'})
145
+
146
+ config.parse!([])
147
+ config.options[:require].should include('some_file')
148
+ end
155
149
 
156
150
  it "provides a helpful error message when a specified profile does not exists in cucumber.yml" do
157
151
  given_cucumber_yml_defined_as({'default' => '--require from/yml', 'html_report' => '--format html'})
@@ -183,9 +177,7 @@ END_OF_MESSAGE
183
177
 
184
178
 
185
179
  ["--no-profile", "-P"].each do |flag|
186
-
187
180
  context 'when none is specified with #{flag}' do
188
-
189
181
  it "disables profiles" do
190
182
  given_cucumber_yml_defined_as({'default' => '-v --require file_specified_in_default_profile.rb'})
191
183
 
@@ -199,13 +191,9 @@ END_OF_MESSAGE
199
191
  config.parse!("#{flag} --require some_file.rb".split(" "))
200
192
  out.string.should =~ /Disabling profiles.../
201
193
  end
202
-
203
194
  end
204
-
205
195
  end
206
196
 
207
-
208
-
209
197
  it "issues a helpful error message when a specified profile exists but is nil or blank" do
210
198
  [nil, ' '].each do |bad_input|
211
199
  given_cucumber_yml_defined_as({'foo' => bad_input})
@@ -240,6 +228,13 @@ END_OF_MESSAGE
240
228
 
241
229
  lambda{config.parse!([])}.should raise_error(expected_error_message)
242
230
  end
231
+
232
+ it "issues a helpful error message when cucumber.yml can not be parsed by ERB" do
233
+ expected_error_message = /cucumber.yml was found, but could not be parsed with ERB. Please refer to cucumber's documentation on correct profile usage./
234
+ given_cucumber_yml_defined_as("<% this_fails %>")
235
+
236
+ lambda{config.parse!([])}.should raise_error(expected_error_message)
237
+ end
243
238
  end
244
239
 
245
240
 
@@ -291,7 +286,13 @@ END_OF_MESSAGE
291
286
  it "should not accept multiple --format options when both use implicit STDOUT" do
292
287
  lambda do
293
288
  config.parse!(%w{--format pretty --format progress})
294
- end.should raise_error("All but one formatter must use --out, only one can print to STDOUT")
289
+ end.should raise_error("All but one formatter must use --out, only one can print to each stream (or STDOUT)")
290
+ end
291
+
292
+ it "should not accept multiple --out streams pointing to the same place" do
293
+ lambda do
294
+ config.parse!(%w{--format pretty --out file1 --format progress --out file1})
295
+ end.should raise_error("All but one formatter must use --out, only one can print to each stream (or STDOUT)")
295
296
  end
296
297
 
297
298
  it "should associate --out to previous --format" do
@@ -86,6 +86,36 @@ module Cucumber
86
86
  end
87
87
  end
88
88
 
89
+ describe "setup step sequence" do
90
+
91
+ it "should load files and execute hooks in order" do
92
+ Configuration.stub!(:new).and_return(configuration = mock('configuration', :null_object => true))
93
+ step_mother = mock('step mother', :null_object => true)
94
+ configuration.stub!(:drb?).and_return false
95
+ cli = Main.new(%w{--verbose example.feature}, @out)
96
+ cli.stub!(:require)
97
+
98
+ configuration.stub!(:support_to_load).and_return(['support'])
99
+ configuration.stub!(:step_defs_to_load).and_return(['step defs'])
100
+
101
+ # Support must be loaded first to ensure post configuration hook can
102
+ # run before anything else.
103
+ step_mother.should_receive(:load_code_files).with(['support']).ordered
104
+ # The post configuration hook/s (if any) need to be run next to enable
105
+ # extensions to do their thing before features are loaded
106
+ step_mother.should_receive(:after_configuration).with(configuration).ordered
107
+ # Feature files must be loaded before step definitions are required.
108
+ # This is because i18n step methods are only aliased when
109
+ # features are loaded. If we swap the order, the requires
110
+ # will fail.
111
+ step_mother.should_receive(:load_plain_text_features).ordered
112
+ step_mother.should_receive(:load_code_files).with(['step defs']).ordered
113
+
114
+ cli.execute!(step_mother)
115
+ end
116
+
117
+ end
118
+
89
119
  [ProfilesNotDefinedError, YmlLoadError, ProfileNotFound].each do |exception_klass|
90
120
 
91
121
  it "rescues #{exception_klass}, prints the message to the error stream and returns true" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.98
4
+ version: 0.3.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Aslak Helles\xC3\xB8y"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-25 00:00:00 -05:00
12
+ date: 2009-09-03 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -346,6 +346,7 @@ files:
346
346
  - features/junit_formatter.feature
347
347
  - features/language_from_header.feature
348
348
  - features/multiline_names.feature
349
+ - features/post_configuration_hook.feature
349
350
  - features/profiles.feature
350
351
  - features/rake_task.feature
351
352
  - features/report_called_undefined_steps.feature