aslakhellesoy-cucumber 0.1.99.15 → 0.1.99.17

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.
@@ -94,6 +94,7 @@ pure Ruby users have been enjoying for a while.
94
94
  * Run cucumber --language LANG help to see keywords for a given language. (Aslak Hellesøy)
95
95
  * Multiline arguments (tables and """ strings) are printed in the output. (Aslak Hellesøy)
96
96
  * It's no longer necessary to compile the Treetop grammar when adding a new language. Localised parser is generated at runtime. (Aslak Hellesøy)
97
+ * New --guess option tries to guess the best step definition match instead of raising Cucumber::Multiple. (Jake Howerton)
97
98
 
98
99
  === Removed features
99
100
  * "GivenScenario" is gone. Instead you can call Steps from Steps, or wait for "Background (#153)"
@@ -138,6 +138,9 @@ examples/test_unit/features/test_unit.feature
138
138
  examples/tickets/Rakefile
139
139
  examples/tickets/cucumber.yml
140
140
  examples/tickets/features/172.feature
141
+ examples/tickets/features/177-1.feature
142
+ examples/tickets/features/177-2.feature
143
+ examples/tickets/features/180.feature
141
144
  examples/tickets/features/lib/eatting_machine.rb
142
145
  examples/tickets/features/lib/pantry.rb
143
146
  examples/tickets/features/scenario_outline.feature
@@ -188,6 +191,7 @@ lib/cucumber/ast/table.rb
188
191
  lib/cucumber/ast/tags.rb
189
192
  lib/cucumber/ast/visitor.rb
190
193
  lib/cucumber/broadcaster.rb
194
+ lib/cucumber/cli/configuration.rb
191
195
  lib/cucumber/cli/language_help_formatter.rb
192
196
  lib/cucumber/cli/main.rb
193
197
  lib/cucumber/core_ext/exception.rb
@@ -240,6 +244,7 @@ spec/cucumber/ast/scenario_spec.rb
240
244
  spec/cucumber/ast/step_spec.rb
241
245
  spec/cucumber/ast/table_spec.rb
242
246
  spec/cucumber/broadcaster_spec.rb
247
+ spec/cucumber/cli/configuration_spec.rb
243
248
  spec/cucumber/cli/main_spec.rb
244
249
  spec/cucumber/core_ext/proc_spec.rb
245
250
  spec/cucumber/core_ext/string_spec.rb
@@ -0,0 +1,29 @@
1
+ Users want to know that nobody can masquerade as them. We want to extend trust
2
+ only to visitors who present the appropriate credentials. Everyone wants this
3
+ identity verification to be as secure and convenient as possible.
4
+
5
+ Feature: Logging in
6
+ As an anonymous user with an account
7
+ I want to log in to my account
8
+ So that I can be myself
9
+
10
+ #
11
+ # Log in: get form
12
+ #
13
+ Scenario: Anonymous user can get a login form.
14
+ Given I am logged out
15
+ When I go to "/login"
16
+ Then I should be at the "sessions/new" page
17
+
18
+ #
19
+ # Log in successfully, but don't remember me
20
+ #
21
+ Scenario: Anonymous user can log in
22
+ Given an "activated" user named "reggie" exists
23
+ And I am logged out
24
+ When I go to "/login"
25
+ And I fill in "Login" with "reggie"
26
+ And I fill in "Password" with "password"
27
+ And I press "Log in"
28
+ Then I should be at the "dashboard/index" page
29
+
@@ -0,0 +1,21 @@
1
+ Visitors may create an account, but for those who are not already in the
2
+ system an someone must activate the account for them before it can be used.
3
+
4
+ Feature: Activating an account
5
+ As a registered, but not yet activated, user
6
+ I want to be able to activate my account
7
+ So that I can log in to the site
8
+
9
+ Scenario: Not-yet-activated user can activate her account
10
+ Given a registered user named 'Reggie' # need to rewrite
11
+ # And the user has activation_code: 'activate_me', activated_at: nil!
12
+ # And we try hard to remember the user's updated_at, and created_at
13
+ # When she goes to /activate/activate_me
14
+ # Then she should be redirected to 'login'
15
+ # When she follows that redirect!
16
+ # Then she should see a notice message 'Signup complete!'
17
+ # And a user with login: 'reggie' should exist
18
+ # And the user should have login: 'reggie', and email: 'registered@example.com'
19
+ # And the user's activation_code should be nil
20
+ # And the user's activated_at should not be nil
21
+ # And she should not be logged in
@@ -0,0 +1,7 @@
1
+ Feature: Cucumber command line
2
+ In order to write better software
3
+ Developers should be able to execute requirements as tests
4
+
5
+
6
+ Scenario: Pending Scenario at the end of a file with whitespace after it
7
+
@@ -28,7 +28,7 @@ Feature: Cucumber command line
28
28
  @two @three
29
29
  Scenario: Missing
30
30
  Given missing
31
- Undefined step: "missing" (Cucumber::StepMother::Undefined)
31
+ Undefined step: "missing" (Cucumber::Undefined)
32
32
  features/sample.feature:6:in `Given missing'
33
33
 
34
34
  1 scenario
@@ -10,12 +10,12 @@ Feature: Cucumber command line
10
10
 
11
11
  Scenario: Call directly # features/call_undefined_step_from_step_def.feature:3
12
12
  Given a step definition that calls an undefined step # features/step_definitions/sample_steps.rb:19
13
- Undefined step: "this does not exist" (Cucumber::StepMother::Undefined)
13
+ Undefined step: "this does not exist" (Cucumber::Undefined)
14
14
  ./features/step_definitions/sample_steps.rb:20:in `/^a step definition that calls an undefined step$/'
15
15
 
16
16
  Scenario: Call via another # features/call_undefined_step_from_step_def.feature:6
17
17
  Given call step "a step definition that calls an undefined step" # features/step_definitions/sample_steps.rb:23
18
- Undefined step: "this does not exist" (Cucumber::StepMother::Undefined)
18
+ Undefined step: "this does not exist" (Cucumber::Undefined)
19
19
  ./features/step_definitions/sample_steps.rb:20:in `/^a step definition that calls an undefined step$/'
20
20
 
21
21
  2 scenarios
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'spec/expectations'
2
3
  require 'fileutils'
3
4
 
@@ -0,0 +1,67 @@
1
+ # http://blog.nicksieger.com/articles/2009/01/10/jruby-1-1-6-gems-in-a-jar
2
+
3
+ USE_JRUBY_VERSION = '1.1.6'
4
+ USE_JBEHAVE_VERSION = '2.1'
5
+ USE_JUNIT_VERSION = '4.5'
6
+ USE_HAMCREST_VERSION = '1.1'
7
+ CUCUMBER_VERSIONED = "cucumber-#{Cucumber::VERSION::STRING}"
8
+
9
+ task :jar => [
10
+ :clean,
11
+ 'jar:download_jruby',
12
+ 'jar:install_gems',
13
+ 'jar:bundle_gems',
14
+ 'jar:download_jars_deps',
15
+ 'jar:unpack_jar_deps',
16
+ 'jar:bundle_jars',
17
+ 'jar:fix_gem_binaries',
18
+ 'jar:test_jar'
19
+ ]
20
+
21
+ namespace :jar do
22
+ task :download_jruby do
23
+ sh "wget http://dist.codehaus.org/jruby/#{USE_JRUBY_VERSION}/jruby-complete-#{USE_JRUBY_VERSION}.jar -O #{CUCUMBER_VERSIONED}.jar"
24
+ end
25
+
26
+ task :install_gems => :gem do
27
+ mkdir 'pkg/jar_gems'
28
+ sh "java -jar #{CUCUMBER_VERSIONED}.jar -S gem install -i ./pkg/jar_gems pkg/#{CUCUMBER_VERSIONED}.gem --no-ri --no-rdoc"
29
+ end
30
+
31
+ task :bundle_gems do
32
+ sh "jar uf #{CUCUMBER_VERSIONED}.jar -C pkg/jar_gems ."
33
+ end
34
+
35
+ task :download_jars_deps do
36
+ mkdir 'pkg/jar_deps'
37
+ sh "wget http://repository.codehaus.org/org/jbehave/jbehave-core/#{USE_JBEHAVE_VERSION}/jbehave-core-#{USE_JBEHAVE_VERSION}.jar -O pkg/jar_deps/jbehave-core-#{USE_JBEHAVE_VERSION}.jar"
38
+ sh "wget http://mirrors.ibiblio.org/pub/mirrors/maven2/junit/junit/#{USE_JUNIT_VERSION}/junit-#{USE_JUNIT_VERSION}.jar -O pkg/jar_deps/junit-#{USE_JUNIT_VERSION}.jar"
39
+ sh "wget http://hamcrest.googlecode.com/files/hamcrest-all-#{USE_HAMCREST_VERSION}.jar -O pkg/jar_deps/hamcrest-all-#{USE_HAMCREST_VERSION}.jar"
40
+ end
41
+
42
+ task :unpack_jar_deps do
43
+ Dir.chdir 'pkg/jar_deps' do
44
+ Dir['*.jar'].each do |jar|
45
+ sh "jar xvf #{jar}"
46
+ rm_rf jar
47
+ rm_rf 'META-INF'
48
+ end
49
+ end
50
+ end
51
+
52
+ task :bundle_jars do
53
+ sh "jar uf #{CUCUMBER_VERSIONED}.jar -C pkg/jar_deps ."
54
+ end
55
+
56
+ task :fix_gem_binaries do
57
+ mkdir_p 'pkg/gem_binaries/META-INF/jruby.home'
58
+ Dir.chdir 'pkg/gem_binaries/META-INF/jruby.home' do
59
+ sh "jar xvf ../../../../#{CUCUMBER_VERSIONED}.jar bin"
60
+ end
61
+ sh "jar uf #{CUCUMBER_VERSIONED}.jar -C pkg/gem_binaries ."
62
+ end
63
+
64
+ task :test_jar do
65
+ sh "java -cp examples/jbehave/target/classes -jar #{CUCUMBER_VERSIONED}.jar -S cucumber examples/jbehave/features"
66
+ end
67
+ end
@@ -3,7 +3,6 @@ $:.unshift(File.dirname(__FILE__)) unless
3
3
 
4
4
  require 'yaml'
5
5
  require 'cucumber/platform'
6
- require 'rubygems'
7
6
  require 'cucumber/parser'
8
7
  require 'cucumber/version'
9
8
  require 'cucumber/step_mother'
@@ -104,14 +104,14 @@ module Cucumber
104
104
  else
105
105
  @status = :skipped
106
106
  end
107
- rescue StepMother::Undefined => exception
107
+ rescue Undefined => exception
108
108
  if visitor.options[:strict]
109
109
  exception.set_backtrace([])
110
110
  failed(exception)
111
111
  else
112
112
  @status = :undefined
113
113
  end
114
- rescue StepMother::Pending => exception
114
+ rescue Pending => exception
115
115
  visitor.options[:strict] ? failed(exception) : @status = :pending
116
116
  rescue Exception => exception
117
117
  failed(exception)
@@ -0,0 +1,336 @@
1
+ module Cucumber
2
+ module Cli
3
+ class YmlLoadError < StandardError; end
4
+
5
+ class Configuration
6
+ FORMATS = %w{pretty profile progress rerun}
7
+ DEFAULT_FORMAT = 'pretty'
8
+
9
+ attr_reader :paths
10
+ attr_reader :options
11
+
12
+ def initialize(out_stream = STDOUT, error_stream = STDERR)
13
+ @out_stream = out_stream
14
+ @error_stream = error_stream
15
+
16
+ @paths = []
17
+ @options = default_options
18
+ @active_format = DEFAULT_FORMAT
19
+ end
20
+
21
+ def parse!(args)
22
+ @args = args
23
+ return parse_args_from_profile('default') if @args.empty?
24
+ @args.extend(::OptionParser::Arguable)
25
+
26
+ @args.options do |opts|
27
+ opts.banner = ["Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+", "",
28
+ "Examples:",
29
+ "cucumber examples/i18n/en/features",
30
+ "cucumber --language it examples/i18n/it/features/somma.feature:6:98:113",
31
+ "cucumber -n -i http://rubyurl.com/eeCl", "", "",
32
+ ].join("\n")
33
+ opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR",
34
+ "Require files before executing the features. If this",
35
+ "option is not specified, all *.rb files that are",
36
+ "siblings or below the features will be loaded auto-",
37
+ "matically. Automatic loading is disabled when this",
38
+ "option is specified, and all loading becomes explicit.",
39
+ "Files under directories named \"support\" are always",
40
+ "loaded first.",
41
+ "This option can be specified multiple times.") do |v|
42
+ @options[:require] ||= []
43
+ @options[:require] << v
44
+ end
45
+ opts.on("-l LANG", "--language LANG",
46
+ "Specify language for features (Default: #{@options[:lang]})",
47
+ %{Run with "--language help" to see all languages},
48
+ %{Run with "--language LANG help" to list keywords for LANG}) do |v|
49
+ if v == 'help'
50
+ list_languages
51
+ elsif args==['help']
52
+ list_keywords(v)
53
+ else
54
+ @options[:lang] = v
55
+ end
56
+ end
57
+ opts.on("-f FORMAT", "--format FORMAT",
58
+ "How to format features (Default: #{DEFAULT_FORMAT})",
59
+ "Available formats: #{FORMATS.join(", ")}",
60
+ "You can also provide your own formatter classes as long",
61
+ "as they have been previously required using --require or",
62
+ "if they are in the folder structure such that cucumber",
63
+ "will require them automatically.",
64
+ "This option can be specified multiple times.") do |v|
65
+ @options[:formats][v] = @out_stream
66
+ @active_format = v
67
+ end
68
+ opts.on("-o", "--out FILE",
69
+ "Write output to a file instead of STDOUT. This option",
70
+ "applies to the previously specified --format, or the",
71
+ "default format if no format is specified.") do |v|
72
+ @options[:formats][@active_format] = v
73
+ end
74
+ opts.on("-t TAGS", "--tags TAGS",
75
+ "Only execute the features or scenarios with the specified tags.",
76
+ "TAGS must be comma-separated without spaces.") do |v|
77
+ @options[:tags] = v.split(",")
78
+ end
79
+ opts.on("-s SCENARIO", "--scenario SCENARIO",
80
+ "Only execute the scenario with the given name. If this option",
81
+ "is given more than once, run all the specified scenarios.") do |v|
82
+ @options[:scenario_names] << v
83
+ end
84
+ opts.on("-e", "--exclude PATTERN", "Don't run feature files matching PATTERN") do |v|
85
+ @options[:excludes] << v
86
+ end
87
+ opts.on("-p", "--profile PROFILE", "Pull commandline arguments from cucumber.yml.") do |v|
88
+ parse_args_from_profile(v)
89
+ end
90
+ opts.on("-c", "--[no-]color",
91
+ "Whether or not to use ANSI color in the output. Cucumber decides",
92
+ "based on your platform and the output destination if not specified.") do |v|
93
+ Term::ANSIColor.coloring = v
94
+ end
95
+ opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
96
+ "Implies --quiet.") do
97
+ @options[:dry_run] = true
98
+ @quiet = true
99
+ end
100
+ opts.on("-a", "--autoformat DIRECTORY",
101
+ "Reformats (pretty prints) feature files and write them to DIRECTORY.",
102
+ "Be careful if you choose to overwrite the originals.",
103
+ "Implies --dry-run --formatter pretty.") do |directory|
104
+ @options[:autoformat] = directory
105
+ Term::ANSIColor.coloring = false
106
+ @options[:dry_run] = true
107
+ @quiet = true
108
+ end
109
+ opts.on("-m", "--no-multiline",
110
+ "Don't print multiline strings and tables under steps.") do
111
+ @options[:no_multiline] = true
112
+ end
113
+ opts.on("-n", "--no-source",
114
+ "Don't print the file and line of the step definition with the steps.") do
115
+ @options[:source] = false
116
+ end
117
+ opts.on("-i", "--no-snippets", "Don't print snippets for pending steps.") do
118
+ @options[:snippets] = false
119
+ end
120
+ opts.on("-q", "--quiet", "Alias for --no-snippets --no-source.") do
121
+ @quiet = true
122
+ end
123
+ opts.on("-b", "--backtrace", "Show full backtrace for all errors.") do
124
+ Exception.cucumber_full_backtrace = true
125
+ end
126
+ opts.on("--strict", "Fail if there are any undefined steps.") do
127
+ @options[:strict] = true
128
+ end
129
+ opts.on("-v", "--verbose", "Show the files and features loaded.") do
130
+ @options[:verbose] = true
131
+ end
132
+ opts.on("-g", "--guess", "Guess best match for Ambiguous steps.") do
133
+ @options[:guess] = true
134
+ end
135
+ opts.on_tail("--version", "Show version.") do
136
+ @out_stream.puts VERSION::STRING
137
+ Kernel.exit
138
+ end
139
+ opts.on_tail("--help", "You're looking at it.") do
140
+ @out_stream.puts opts.help
141
+ Kernel.exit
142
+ end
143
+ end.parse!
144
+
145
+ @options[:formats]['pretty'] = @out_stream if @options[:formats].empty?
146
+
147
+ @options[:snippets] = true if !@quiet && @options[:snippets].nil?
148
+ @options[:source] = true if !@quiet && @options[:source].nil?
149
+
150
+ # Whatever is left after option parsing is the FILE arguments
151
+ @paths += args
152
+ end
153
+
154
+ def ast_filter
155
+ Ast::Filter.new(@options)
156
+ end
157
+
158
+ def verbose?
159
+ @options[:verbose]
160
+ end
161
+
162
+ def strict?
163
+ @options[:strict]
164
+ end
165
+
166
+ def guess?
167
+ !!@options[:guess]
168
+ end
169
+
170
+ def load_language
171
+ Cucumber.load_language(@options[:lang])
172
+
173
+ if Cucumber.language_incomplete?
174
+ list_keywords(Cucumber.lang)
175
+ end
176
+ end
177
+
178
+ def build_formatter_broadcaster(step_mother)
179
+ return Formatter::Pretty.new(step_mother, nil, @options) if @options[:autoformat]
180
+ formatters = @options[:formats].map do |format, out|
181
+ if String === out # file name
182
+ out = File.open(out, Cucumber.file_mode('w'))
183
+ at_exit do
184
+ out.flush
185
+ out.close
186
+ end
187
+ end
188
+
189
+ begin
190
+ formatter_class = formatter_class(format)
191
+ formatter_class.new(step_mother, out, @options)
192
+ rescue Exception => e
193
+ exit_with_error("Error creating formatter: #{format}", e)
194
+ end
195
+ end
196
+
197
+ broadcaster = Broadcaster.new(formatters)
198
+ broadcaster.options = @options
199
+ return broadcaster
200
+ end
201
+
202
+ def formatter_class(format)
203
+ case format
204
+ when 'pretty' then Formatter::Pretty
205
+ when 'progress' then Formatter::Progress
206
+ when 'profile' then Formatter::Profile
207
+ when 'rerun' then Formatter::Rerun
208
+ else
209
+ constantize(format)
210
+ end
211
+ end
212
+
213
+ def files_to_require
214
+ requires = @options[:require] || feature_dirs
215
+ files = requires.map do |path|
216
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
217
+ File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
218
+ end.flatten.uniq
219
+ files.sort { |a,b| (b =~ %r{/support/} || -1) <=> (a =~ %r{/support/} || -1) }.reject{|f| f =~ /^http/}
220
+ end
221
+
222
+ def feature_files
223
+ potential_feature_files = @paths.map do |path|
224
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
225
+ path = path.chomp('/')
226
+ File.directory?(path) ? Dir["#{path}/**/*.feature"] : path
227
+ end.flatten.uniq
228
+
229
+ @options[:excludes].each do |exclude|
230
+ potential_feature_files.reject! do |path|
231
+ path =~ /#{Regexp.escape(exclude)}/
232
+ end
233
+ end
234
+
235
+ potential_feature_files
236
+ end
237
+
238
+ protected
239
+
240
+ def feature_dirs
241
+ feature_files.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
242
+ end
243
+
244
+ def constantize(camel_cased_word)
245
+ names = camel_cased_word.split('::')
246
+ names.shift if names.empty? || names.first.empty?
247
+
248
+ constant = Object
249
+ names.each do |name|
250
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
251
+ end
252
+ constant
253
+ end
254
+
255
+ def parse_args_from_profile(profile)
256
+ unless cucumber_yml.has_key?(profile)
257
+ return(exit_with_error <<-END_OF_ERROR)
258
+ Could not find profile: '#{profile}'
259
+
260
+ Defined profiles in cucumber.yml:
261
+ * #{cucumber_yml.keys.join("\n * ")}
262
+ END_OF_ERROR
263
+ end
264
+
265
+ args_from_yml = cucumber_yml[profile] || ''
266
+
267
+ if !args_from_yml.is_a?(String)
268
+ exit_with_error "Profiles must be defined as a String. The '#{profile}' profile was #{args_from_yml.inspect} (#{args_from_yml.class}).\n"
269
+ elsif args_from_yml =~ /^\s*$/
270
+ exit_with_error "The 'foo' profile in cucumber.yml was blank. Please define the command line arguments for the 'foo' profile in cucumber.yml.\n"
271
+ else
272
+ parse!(args_from_yml.split(' '))
273
+ end
274
+
275
+ rescue YmlLoadError => e
276
+ exit_with_error(e.message)
277
+ end
278
+
279
+ def cucumber_yml
280
+ return @cucumber_yml if @cucumber_yml
281
+ unless File.exist?('cucumber.yml')
282
+ raise(YmlLoadError,"cucumber.yml was not found. Please refer to cucumber's documentaion 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")
283
+ end
284
+
285
+ require 'yaml'
286
+ begin
287
+ @cucumber_yml = YAML::load(IO.read('cucumber.yml'))
288
+ rescue Exception => e
289
+ raise(YmlLoadError,"cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentaion on correct profile usage.\n")
290
+ end
291
+
292
+ if @cucumber_yml.nil? || !@cucumber_yml.is_a?(Hash)
293
+ raise(YmlLoadError,"cucumber.yml was found, but was blank or malformed. Please refer to cucumber's documentaion on correct profile usage.\n")
294
+ end
295
+
296
+ return @cucumber_yml
297
+ end
298
+
299
+ def list_keywords(lang)
300
+ unless Cucumber::LANGUAGES[lang]
301
+ exit_with_error("No language with key #{lang}")
302
+ end
303
+ LanguageHelpFormatter.list_keywords(@out_stream, lang)
304
+ Kernel.exit
305
+ end
306
+
307
+ def list_languages
308
+ LanguageHelpFormatter.list_languages(@out_stream)
309
+ Kernel.exit
310
+ end
311
+
312
+ def default_options
313
+ {
314
+ :strict => false,
315
+ :require => nil,
316
+ :lang => 'en',
317
+ :dry_run => false,
318
+ :formats => {},
319
+ :excludes => [],
320
+ :tags => [],
321
+ :scenario_names => []
322
+ }
323
+ end
324
+
325
+ def exit_with_error(error_message, e=nil)
326
+ @error_stream.puts(error_message)
327
+ if e
328
+ @error_stream.puts("#{e.message} (#{e.class})")
329
+ @error_stream.puts(e.backtrace.join("\n"))
330
+ end
331
+ Kernel.exit 1
332
+ end
333
+ end
334
+
335
+ end
336
+ end