cucumber 0.9.4 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/Gemfile +1 -1
  2. data/History.txt +16 -0
  3. data/bin/cucumber +7 -1
  4. data/cucumber.gemspec +5 -4
  5. data/cucumber.yml +1 -1
  6. data/examples/sinatra/features/support/env.rb +1 -4
  7. data/features/background.feature +284 -95
  8. data/features/custom_formatter.feature +3 -73
  9. data/features/execute_with_tag_filter.feature +63 -0
  10. data/features/{negative_tagged_hooks.feature → hooks.feature} +5 -6
  11. data/features/json_formatter.feature +161 -245
  12. data/features/stats_formatters.feature +70 -0
  13. data/features/step_definitions/cucumber_steps.rb +5 -163
  14. data/features/support/env.rb +23 -149
  15. data/features/{tag_logic.feature → tagged_hooks.feature} +11 -52
  16. data/gem_tasks/{features.rake → cucumber.rake} +6 -1
  17. data/{features → legacy_features}/announce.feature +0 -0
  18. data/{features → legacy_features}/api/list_step_defs_as_json.feature +0 -0
  19. data/{features → legacy_features}/api/run_cli_main_with_existing_runtime.feature +0 -0
  20. data/{features → legacy_features}/around_hooks.feature +0 -0
  21. data/{features → legacy_features}/bug_371.feature +0 -0
  22. data/{features → legacy_features}/bug_464.feature +0 -0
  23. data/{features → legacy_features}/bug_475.feature +0 -0
  24. data/{features → legacy_features}/bug_585_tab_indentation.feature +0 -0
  25. data/{features → legacy_features}/bug_600.feature +0 -0
  26. data/{features → legacy_features}/call_steps_from_stepdefs.feature +0 -0
  27. data/{features → legacy_features}/cucumber_cli.feature +9 -9
  28. data/{features → legacy_features}/cucumber_cli_outlines.feature +0 -0
  29. data/{features → legacy_features}/default_snippets.feature +0 -0
  30. data/{features → legacy_features}/diffing.feature +0 -0
  31. data/{features → legacy_features}/drb_server_integration.feature +0 -0
  32. data/{features → legacy_features}/exception_in_after_block.feature +0 -0
  33. data/{features → legacy_features}/exception_in_after_step_block.feature +0 -0
  34. data/{features → legacy_features}/exception_in_before_block.feature +0 -0
  35. data/{features → legacy_features}/exclude_files.feature +0 -0
  36. data/{features → legacy_features}/expand.feature +0 -0
  37. data/{features → legacy_features}/html_formatter.feature +0 -0
  38. data/{features → legacy_features}/html_formatter/a.html +0 -0
  39. data/{features → legacy_features}/junit_formatter.feature +0 -0
  40. data/{features → legacy_features}/language_from_header.feature +0 -0
  41. data/{features → legacy_features}/language_help.feature +0 -0
  42. data/{features → legacy_features}/listener_debugger_formatter.feature +0 -0
  43. data/legacy_features/multiline_names.feature +44 -0
  44. data/{features → legacy_features}/post_configuration_hook.feature +0 -0
  45. data/{features → legacy_features}/profiles.feature +0 -0
  46. data/{features → legacy_features}/rake_task.feature +0 -0
  47. data/{features → legacy_features}/report_called_undefined_steps.feature +0 -0
  48. data/{features → legacy_features}/rerun_formatter.feature +0 -0
  49. data/{features → legacy_features}/simplest.feature +0 -0
  50. data/{features → legacy_features}/snippet.feature +0 -0
  51. data/{features → legacy_features}/snippets_when_using_star_keyword.feature +0 -0
  52. data/legacy_features/step_definitions/cucumber_steps.rb +168 -0
  53. data/{features → legacy_features}/step_definitions/extra_steps.rb +0 -0
  54. data/{features → legacy_features}/step_definitions/simplest_steps.rb +0 -0
  55. data/{features → legacy_features}/step_definitions/wire_steps.rb +1 -0
  56. data/legacy_features/support/env.rb +157 -0
  57. data/{features → legacy_features}/support/env.rb.simplest +0 -0
  58. data/{features → legacy_features}/support/fake_wire_server.rb +0 -0
  59. data/{features → legacy_features}/table_diffing.feature +0 -0
  60. data/{features → legacy_features}/table_mapping.feature +0 -0
  61. data/{features → legacy_features}/transform.feature +0 -0
  62. data/{features → legacy_features}/unicode_table.feature +0 -0
  63. data/{features → legacy_features}/wire_protocol.feature +1 -1
  64. data/{features → legacy_features}/wire_protocol_table_diffing.feature +0 -0
  65. data/{features → legacy_features}/wire_protocol_tags.feature +0 -0
  66. data/{features → legacy_features}/wire_protocol_timeouts.feature +0 -0
  67. data/{features → legacy_features}/work_in_progress.feature +0 -0
  68. data/lib/cucumber/ast/examples.rb +5 -0
  69. data/lib/cucumber/ast/feature.rb +5 -0
  70. data/lib/cucumber/ast/feature_element.rb +5 -0
  71. data/lib/cucumber/ast/scenario_outline.rb +9 -4
  72. data/lib/cucumber/ast/step.rb +5 -0
  73. data/lib/cucumber/ast/step_invocation.rb +4 -0
  74. data/lib/cucumber/ast/table.rb +3 -3
  75. data/lib/cucumber/ast/tree_walker.rb +1 -39
  76. data/lib/cucumber/cli/main.rb +1 -6
  77. data/lib/cucumber/cli/options.rb +1 -2
  78. data/lib/cucumber/formatter/ansicolor.rb +2 -4
  79. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +84 -0
  80. data/lib/cucumber/formatter/gpretty.rb +24 -0
  81. data/lib/cucumber/formatter/html.rb +1 -1
  82. data/lib/cucumber/formatter/io.rb +2 -4
  83. data/lib/cucumber/formatter/json.rb +15 -152
  84. data/lib/cucumber/formatter/json_pretty.rb +5 -6
  85. data/lib/cucumber/formatter/unicode.rb +41 -20
  86. data/lib/cucumber/parser/gherkin_builder.rb +7 -1
  87. data/lib/cucumber/platform.rb +1 -1
  88. data/lib/cucumber/step_match.rb +5 -1
  89. data/spec/cucumber/ast/scenario_outline_spec.rb +11 -8
  90. data/spec/cucumber/ast/table_spec.rb +6 -1
  91. data/spec/cucumber/cli/main_spec.rb +4 -1
  92. metadata +105 -132
  93. data/features/multiline_names.feature +0 -44
  94. data/features/usage_and_stepdefs_formatter.feature +0 -169
  95. data/fixtures/json/features/pystring.feature +0 -8
  96. data/fixtures/self_test/features/background/background_tagged_before_on_outline.feature +0 -12
  97. data/fixtures/self_test/features/background/background_with_name.feature +0 -7
  98. data/fixtures/self_test/features/background/failing_background.feature +0 -12
  99. data/fixtures/self_test/features/background/failing_background_after_success.feature +0 -11
  100. data/fixtures/self_test/features/background/multiline_args_background.feature +0 -32
  101. data/fixtures/self_test/features/background/passing_background.feature +0 -10
  102. data/fixtures/self_test/features/background/pending_background.feature +0 -10
  103. data/fixtures/self_test/features/background/scenario_outline_failing_background.feature +0 -16
  104. data/fixtures/self_test/features/background/scenario_outline_passing_background.feature +0 -16
  105. data/lib/cucumber/formatter/color_io.rb +0 -23
  106. data/lib/cucumber/formatter/tag_cloud.rb +0 -35
  107. data/spec/cucumber/formatter/color_io_spec.rb +0 -29
@@ -2,7 +2,10 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
2
  require 'cucumber/rake/task'
3
3
  require 'cucumber/platform'
4
4
 
5
- Cucumber::Rake::Task.new do |t|
5
+ Cucumber::Rake::Task.new(:features)
6
+
7
+ Cucumber::Rake::Task.new(:legacy_features) do |t|
8
+ t.cucumber_opts = %w{legacy_features}
6
9
  if(Cucumber::JRUBY)
7
10
  t.profile = Cucumber::WINDOWS ? 'jruby_win' : 'jruby'
8
11
  elsif(Cucumber::WINDOWS_MRI)
@@ -12,3 +15,5 @@ Cucumber::Rake::Task.new do |t|
12
15
  end
13
16
  t.rcov = ENV['RCOV']
14
17
  end
18
+
19
+ task :cucumber => [:features, :legacy_features]
@@ -90,7 +90,7 @@ Feature: Cucumber command line
90
90
  """
91
91
 
92
92
  Scenario: Require missing step definition from elsewhere
93
- When I run cucumber -q -r ../../features/step_definitions/extra_steps.rb features/sample.feature:5
93
+ When I run cucumber -q -r ../../legacy_features/step_definitions/extra_steps.rb features/sample.feature:5
94
94
  Then it should pass with
95
95
  """
96
96
  # Feature comment
@@ -196,18 +196,18 @@ Feature: Cucumber command line
196
196
  Feature: multiline
197
197
 
198
198
  Background: I'm a multiline name
199
- which goes on and on and on for three lines
200
- yawn
199
+ which goes on and on and on for three lines
200
+ yawn
201
201
  Given passing without a table
202
202
 
203
203
  Scenario: I'm a multiline name
204
- which goes on and on and on for three lines
205
- yawn
204
+ which goes on and on and on for three lines
205
+ yawn
206
206
  Given passing without a table
207
207
 
208
208
  Scenario Outline: I'm a multiline name
209
- which goes on and on and on for three lines
210
- yawn
209
+ which goes on and on and on for three lines
210
+ yawn
211
211
  Given <state> without a table
212
212
 
213
213
  Examples:
@@ -218,8 +218,8 @@ Feature: Cucumber command line
218
218
  Given <state> without a table
219
219
 
220
220
  Examples: I'm a multiline name
221
- which goes on and on and on for three lines
222
- yawn
221
+ which goes on and on and on for three lines
222
+ yawn
223
223
  | state |
224
224
  | passing |
225
225
 
@@ -0,0 +1,44 @@
1
+ Feature: Multiline description names
2
+ In order to accurately document feature elements
3
+ As a cucumberist
4
+ I want to have multiline names
5
+
6
+ Scenario: multiline scenario
7
+ When I run cucumber features/multiline_name.feature --no-snippets
8
+ Then STDERR should be empty
9
+ Then it should pass with
10
+ """
11
+ Feature: multiline
12
+
13
+ Background: I'm a multiline name # features/multiline_name.feature:3
14
+ which goes on and on and on for three lines
15
+ yawn
16
+ Given passing without a table # features/step_definitions/sample_steps.rb:12
17
+
18
+ Scenario: I'm a multiline name # features/multiline_name.feature:8
19
+ which goes on and on and on for three lines
20
+ yawn
21
+ Given passing without a table # features/step_definitions/sample_steps.rb:12
22
+
23
+ Scenario Outline: I'm a multiline name # features/multiline_name.feature:13
24
+ which goes on and on and on for three lines
25
+ yawn
26
+ Given <state> without a table # features/step_definitions/sample_steps.rb:12
27
+
28
+ Examples:
29
+ | state |
30
+ | passing |
31
+
32
+ Scenario Outline: name # features/multiline_name.feature:21
33
+ Given <state> without a table # features/step_definitions/sample_steps.rb:12
34
+
35
+ Examples: I'm a multiline name
36
+ which goes on and on and on for three lines
37
+ yawn
38
+ | state |
39
+ | passing |
40
+
41
+ 3 scenarios (3 passed)
42
+ 6 steps (6 passed)
43
+
44
+ """
@@ -0,0 +1,168 @@
1
+ # encoding: utf-8
2
+ require 'tempfile'
3
+
4
+ Given /^I am in (.*)$/ do |example_dir_relative_path|
5
+ @current_dir = fixtures_dir(example_dir_relative_path)
6
+ end
7
+
8
+ Given /^a standard Cucumber project directory structure$/ do
9
+ @current_dir = working_dir
10
+ in_current_dir do
11
+ FileUtils.rm_rf 'features' if File.directory?('features')
12
+ FileUtils.mkdir_p 'features/support'
13
+ FileUtils.mkdir 'features/step_definitions'
14
+ end
15
+ end
16
+
17
+ Given /^the (.*) directory is empty$/ do |directory|
18
+ in_current_dir do
19
+ FileUtils.remove_dir(directory) rescue nil
20
+ FileUtils.mkdir 'tmp'
21
+ end
22
+ end
23
+
24
+ Given /^a file named "([^"]*)"$/ do |file_name|
25
+ create_file(file_name, '')
26
+ end
27
+
28
+ Given /^a file named "([^"]*)" with:$/ do |file_name, file_content|
29
+ create_file(file_name, file_content)
30
+ end
31
+
32
+ Given /^the following profiles? (?:are|is) defined:$/ do |profiles|
33
+ create_file('cucumber.yml', profiles)
34
+ end
35
+
36
+ Given /^I am running spork in the background$/ do
37
+ run_spork_in_background
38
+ end
39
+
40
+ Given /^I am running spork in the background on port (\d+)$/ do |port|
41
+ run_spork_in_background(port.to_i)
42
+ end
43
+
44
+ Given /^I am not running (?:.*) in the background$/ do
45
+ # no-op
46
+ end
47
+
48
+ Given /^I have environment variable (\w+) set to "([^"]*)"$/ do |variable, value|
49
+ set_env_var(variable, value)
50
+ end
51
+
52
+ When /^I run cucumber (.*)$/ do |cucumber_opts|
53
+ run "#{Cucumber::RUBY_BINARY} -I rubygems #{cucumber_bin} --no-color #{cucumber_opts} CUCUMBER_OUTPUT_ENCODING=UTF-8"
54
+ end
55
+
56
+ When /^I run rake (.*)$/ do |rake_opts|
57
+ run "rake #{rake_opts} --trace"
58
+ end
59
+
60
+ When /^I run the following Ruby code:$/ do |code|
61
+ run %{#{Cucumber::RUBY_BINARY} -r rubygems -I #{cucumber_lib_dir} -e "#{code}"}
62
+ end
63
+
64
+ Then /^it should (fail|pass)$/ do |success|
65
+ if success == 'fail'
66
+ last_exit_status.should_not == 0
67
+ else
68
+ if last_exit_status != 0
69
+ raise "Failed with exit status #{last_exit_status}\nSTDOUT:\n#{last_stdout}\nSTDERR:\n#{last_stderr}"
70
+ end
71
+ end
72
+ end
73
+
74
+ Then /^it should (fail|pass) with$/ do |success, output|
75
+ unless combined_output.index(output)
76
+ combined_output.should == output
77
+ end
78
+ Then("it should #{success}")
79
+ end
80
+
81
+ Then /^the output should contain:?$/ do |text|
82
+ last_stdout.should include(text)
83
+ end
84
+
85
+ Then /^the output should not contain$/ do |text|
86
+ last_stdout.should_not include(text)
87
+ end
88
+
89
+ Then /^the output should be$/ do |text|
90
+ last_stdout.should == text
91
+ end
92
+
93
+ Then /^it should (fail|pass) with JSON$/ do |success, text|
94
+ JSON.parse(last_stdout).should == JSON.parse(text)
95
+ Then("it should #{success}")
96
+ end
97
+
98
+ Then /^"([^"]*)" should contain$/ do |file, text|
99
+ strip_duration(IO.read(file)).should == text
100
+ end
101
+
102
+ Then /^"([^"]*)" with junit duration "([^"]*)" should contain$/ do |actual_file, duration_replacement, text|
103
+ actual = IO.read(actual_file)
104
+ actual = replace_junit_duration(actual, duration_replacement)
105
+ actual = strip_ruby186_extra_trace(actual)
106
+ actual.should == text
107
+ end
108
+
109
+ Then /^"([^"]*)" should match "(.+?)"$/ do |file, text|
110
+ File.open(file, Cucumber.file_mode('r')).read.should =~ Regexp.new(text)
111
+ end
112
+
113
+ Then /^"([^"]*)" should have the same contents as "([^"]*)"$/ do |actual_file, expected_file|
114
+ actual = IO.read(actual_file)
115
+ actual = replace_duration(actual, '0m30.005s')
116
+ # Comment out to replace expected file. Use with care!
117
+ # File.open(expected_file, "w") {|io| io.write(actual)}
118
+ actual.should == IO.read(expected_file)
119
+ end
120
+
121
+ Then /^STDERR should match$/ do |text|
122
+ last_stderr.should =~ /#{text}/
123
+ end
124
+
125
+ Then /^STDERR should not match$/ do |text|
126
+ last_stderr.should_not =~ /#{text}/
127
+ end
128
+
129
+ Then /^STDERR should be$/ do |text|
130
+ last_stderr.should == text
131
+ end
132
+
133
+ Then /^STDERR should be empty$/ do
134
+ last_stderr.should == ""
135
+ end
136
+
137
+ Then /^"([^"]*)" should exist$/ do |file|
138
+ File.exists?(file).should be_true
139
+ FileUtils.rm(file)
140
+ end
141
+
142
+ Then /^"([^"]*)" should not be required$/ do |file_name|
143
+ last_stdout.should_not include("* #{file_name}")
144
+ end
145
+
146
+ Then /^"([^"]*)" should be required$/ do |file_name|
147
+ last_stdout.should include("* #{file_name}")
148
+ end
149
+
150
+ Then /^exactly these files should be loaded:\s*(.*)$/ do |files|
151
+ last_stdout.scan(/^ \* (.*\.rb)$/).flatten.should == files.split(/,\s+/)
152
+ end
153
+
154
+ Then /^exactly these features should be ran:\s*(.*)$/ do |files|
155
+ last_stdout.scan(/^ \* (.*\.feature)$/).flatten.should == files.split(/,\s+/)
156
+ end
157
+
158
+ Then /^the (.*) profile should be used$/ do |profile|
159
+ last_stdout.should =~ /Using the #{profile} profile/
160
+ end
161
+
162
+ Then /^print output$/ do
163
+ puts last_stdout
164
+ end
165
+
166
+ Then /^the output should contain the following JSON:$/ do |json_string|
167
+ JSON.parse(last_stdout).should == JSON.parse(json_string)
168
+ end
@@ -1,4 +1,5 @@
1
1
  Given /^there is a wire server (running |)on port (\d+) which understands the following protocol:$/ do |running, port, table|
2
+ table.map_column!('response') {|cell| cell.gsub(/\n/, '\n')}
2
3
  protocol = table.hashes
3
4
  @server = FakeWireServer.new(port.to_i, protocol)
4
5
  start_wire_server if running.strip == "running"
@@ -0,0 +1,157 @@
1
+ require 'rubygems'
2
+
3
+ require 'tempfile'
4
+ require 'rspec/expectations'
5
+ require 'fileutils'
6
+ require 'forwardable'
7
+ require 'cucumber/formatter/unicode'
8
+ # This is to force miniunit to be loaded on 1.9.2, and verify that we can still run with --profile. See:
9
+ # * disable_mini_test_autorun.rb and
10
+ # * http://groups.google.com/group/cukes/browse_thread/thread/5682d41436e235d7
11
+ # * https://rspec.lighthouseapp.com/projects/16211/tickets/677-cucumber-093-prevents-testunit-from-running
12
+ require 'test/unit'
13
+
14
+ class CucumberWorld
15
+ extend Forwardable
16
+ def_delegators CucumberWorld, :fixtures_dir, :self_test_dir, :working_dir, :cucumber_lib_dir
17
+
18
+ def self.fixtures_dir(subdir=nil)
19
+ @fixtures_dir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../fixtures'))
20
+ subdir ? File.join(@fixtures_dir, subdir) : @fixtures_dir
21
+ end
22
+
23
+ def self.self_test_dir
24
+ @self_test_dir ||= fixtures_dir('self_test')
25
+ end
26
+
27
+ def self.working_dir
28
+ @working_dir ||= fixtures_dir('self_test/tmp')
29
+ end
30
+
31
+ def cucumber_lib_dir
32
+ @cucumber_lib_dir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
33
+ end
34
+
35
+ # Don't use Cucumber::BINARY (which is the binary used to start the "outer" cucumber)
36
+ # Instead we force the use of this codebase's cucumber bin script.
37
+ # This allows us to run cucumber's cukes with an older, stable cucumber.
38
+ def cucumber_bin
39
+ File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
40
+ end
41
+
42
+ def initialize
43
+ @current_dir = self_test_dir
44
+ end
45
+
46
+ private
47
+ attr_reader :last_exit_status, :last_stderr
48
+
49
+ # The last standard out, with the duration line taken out (unpredictable)
50
+ def last_stdout
51
+ strip_1_9_paths(strip_duration(@last_stdout))
52
+ end
53
+
54
+ def combined_output
55
+ last_stdout + "\n" + last_stderr
56
+ end
57
+
58
+ def strip_duration(s)
59
+ s.gsub(/^\d+m\d+\.\d+s\n/m, "")
60
+ end
61
+
62
+ def strip_1_9_paths(s)
63
+ s.gsub(/#{Dir.pwd}\/fixtures\/self_test\/tmp/m, ".").gsub(/#{Dir.pwd}\/fixtures\/self_test/m, ".")
64
+ end
65
+
66
+ def replace_duration(s, replacement)
67
+ s.gsub(/\d+m\d+\.\d+s/m, replacement)
68
+ end
69
+
70
+ def replace_junit_duration(s, replacement)
71
+ s.gsub(/\d+\.\d\d+/m, replacement)
72
+ end
73
+
74
+ def strip_ruby186_extra_trace(s)
75
+ s.gsub(/^.*\.\/features\/step_definitions(.*)\n/, "")
76
+ end
77
+
78
+ def create_file(file_name, file_content)
79
+ file_content.gsub!("CUCUMBER_LIB", "'#{cucumber_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
80
+ in_current_dir do
81
+ FileUtils.mkdir_p(File.dirname(file_name)) unless File.directory?(File.dirname(file_name))
82
+ File.open(file_name, 'w') { |f| f << file_content }
83
+ end
84
+ end
85
+
86
+ def set_env_var(variable, value)
87
+ @original_env_vars ||= {}
88
+ @original_env_vars[variable] = ENV[variable]
89
+ ENV[variable] = value
90
+ end
91
+
92
+ def background_jobs
93
+ @background_jobs ||= []
94
+ end
95
+
96
+ def in_current_dir(&block)
97
+ Dir.chdir(@current_dir, &block)
98
+ end
99
+
100
+ def run(command)
101
+ stderr_file = Tempfile.new('cucumber')
102
+ stderr_file.close
103
+ in_current_dir do
104
+ mode = Cucumber::RUBY_1_9 ? {:external_encoding=>"UTF-8"} : 'r'
105
+ IO.popen("#{command} 2> #{stderr_file.path}", mode) do |io|
106
+ @last_stdout = io.read
107
+ end
108
+
109
+ @last_exit_status = $?.exitstatus
110
+ end
111
+ @last_stderr = IO.read(stderr_file.path)
112
+ end
113
+
114
+ def run_spork_in_background(port = nil)
115
+ require 'spork'
116
+
117
+ pid = fork
118
+ in_current_dir do
119
+ if pid
120
+ background_jobs << pid
121
+ else
122
+ # STDOUT.close
123
+ # STDERR.close
124
+ port_arg = port ? "-p #{port}" : ''
125
+ cmd = "#{Cucumber::RUBY_BINARY} -I #{Cucumber::LIBDIR} #{Spork::BINARY} cuc #{port_arg}"
126
+ exec cmd
127
+ end
128
+ end
129
+ sleep 1.0
130
+ end
131
+
132
+ def terminate_background_jobs
133
+ background_jobs.each do |pid|
134
+ Process.kill(Signal.list['TERM'], pid)
135
+ end
136
+ end
137
+
138
+ def restore_original_env_vars
139
+ @original_env_vars.each { |variable, value| ENV[variable] = value } if @original_env_vars
140
+ end
141
+
142
+ end
143
+
144
+ World do
145
+ CucumberWorld.new
146
+ end
147
+
148
+ Before do
149
+ FileUtils.rm_rf CucumberWorld.working_dir
150
+ FileUtils.mkdir CucumberWorld.working_dir
151
+ end
152
+
153
+ After do
154
+ FileUtils.rm_rf CucumberWorld.working_dir unless ENV['KEEP_FILES']
155
+ terminate_background_jobs
156
+ restore_original_env_vars
157
+ end