diff --git a/cucumber.yml b/cucumber.yml index 95e8965cb47..0287c10655b 100644 --- a/cucumber.yml +++ b/cucumber.yml @@ -10,7 +10,7 @@ rescue LoadError std_opts << ' --tags ~@rspec2' end %> -default: <%= std_opts %> +default: <%= std_opts %> --dotcucumber features/.cucumber jruby: <%= std_opts %> --tags ~@spork --tags ~@wire jruby_win: <%= std_opts %> --tags ~@spork --tags ~@wire CUCUMBER_FORWARD_SLASH_PATHS=true windows_mri: <%= std_opts %> --tags ~@spork --tags ~@wire --tags ~@needs-many-fonts CUCUMBER_FORWARD_SLASH_PATHS=true diff --git a/features/.cucumber/stepdefs.json b/features/.cucumber/stepdefs.json new file mode 100644 index 00000000000..1bb72945866 --- /dev/null +++ b/features/.cucumber/stepdefs.json @@ -0,0 +1,298 @@ +{ + "^I'm using a clean gemset \"([^\"]*)\"$": [ + + ], + "^a directory named \"([^\"]*)\"$": [ + + ], + "^a file named \"([^\"]*)\" with:$": [ + "a file named \"features/doc_string.feature\" with:", + "a file named \"features/f.feature\" with:", + "a file named \"features/only_background_and_hooks.feature\" with:", + "a file named \"features/only_background_and_hooks_steps.rb\" with:", + "a file named \"features/step_definitions/doc_string_steps.rb\" with:", + "a file named \"features/step_definitions/multiline_steps.rb\" with:", + "a file named \"features/step_definitions/steps.rb\" with:", + "a file named \"features/support/hooks.rb\" with:", + "a file named \"features/support/ze/formator.rb\" with:" + ], + "^a (\\d+) byte file named \"([^\"]*)\"$": [ + + ], + "^an empty file named \"([^\"]*)\"$": [ + + ], + "^I write to \"([^\"]*)\" with:$": [ + + ], + "^I overwrite \"([^\"]*)\" with:$": [ + + ], + "^I append to \"([^\"]*)\" with:$": [ + + ], + "^I append to \"([^\"]*)\" with \"([^\"]*)\"$": [ + + ], + "^I remove the file \"([^\"]*)\"$": [ + + ], + "^I cd to \"([^\"]*)\"$": [ + + ], + "^I run \"(.*)\"$": [ + + ], + "^I run `([^`]*)`$": [ + "I run `cucumber -f stepdefs --dry-run`", + "I run `cucumber -f usage --dry-run`", + "I run `cucumber -q -t @one -t @three features/tagulicious.feature`", + "I run `cucumber -q -t @one,@three features/tagulicious.feature`", + "I run `cucumber -q features/background_tagged_before_on_outline.feature`", + "I run `cucumber -q features/failing_background.feature`", + "I run `cucumber -q features/failing_background_after_success.feature`", + "I run `cucumber -q features/multiline_args_background.feature`", + "I run `cucumber -q features/passing_background.feature:9`", + "I run `cucumber -q features/passing_background.feature`", + "I run `cucumber -q features/pending_background.feature`", + "I run `cucumber -q features/scenario_outline_failing_background.feature`", + "I run `cucumber -q features/scenario_outline_passing_background.feature`", + "I run `cucumber -q features/tagulicious.feature`", + "I run `cucumber features/f.feature:2`", + "I run `cucumber features/f.feature:6`", + "I run `cucumber features/only_background_and_hooks.feature`", + "I run `cucumber`" + ], + "^I successfully run \"(.*)\"$": [ + + ], + "^I successfully run `([^`]*)`$": [ + + ], + "^I run \"([^\"]*)\" interactively$": [ + + ], + "^I run `([^`]*)` interactively$": [ + + ], + "^I type \"([^\"]*)\"$": [ + + ], + "^the output should contain \"([^\"]*)\"$": [ + "the output should contain \"WARNING\"" + ], + "^the output from \"([^\"]*)\" should contain \"([^\"]*)\"$": [ + + ], + "^the output from \"([^\"]*)\" should not contain \"([^\"]*)\"$": [ + + ], + "^the output should not contain \"([^\"]*)\"$": [ + + ], + "^the output should contain:$": [ + "the output should contain:" + ], + "^the output should not contain:$": [ + + ], + "^the output should contain exactly \"([^\"]*)\"$": [ + + ], + "^the output should contain exactly:$": [ + + ], + "^the output should match \\/([^\\/]*)\\/$": [ + + ], + "^the output should match:$": [ + + ], + "^the exit status should be (\\d+)$": [ + + ], + "^the exit status should not be (\\d+)$": [ + + ], + "^it should (pass|fail) with:$": [ + "it should fail with:", + "it should pass with:" + ], + "^it should (pass|fail) with exactly:$": [ + "it should fail with exactly:", + "it should pass with exactly:" + ], + "^it should (pass|fail) with regexp?:$": [ + + ], + "^the stderr should contain \"([^\"]*)\"$": [ + + ], + "^the stderr should contain:$": [ + + ], + "^the stderr should contain exactly:$": [ + + ], + "^the stdout should contain \"([^\"]*)\"$": [ + + ], + "^the stdout should contain:$": [ + + ], + "^the stdout should contain exactly:$": [ + + ], + "^the stderr should not contain \"([^\"]*)\"$": [ + + ], + "^the stderr should not contain:$": [ + + ], + "^the stdout should not contain \"([^\"]*)\"$": [ + + ], + "^the stdout should not contain:$": [ + + ], + "^the stdout from \"([^\"]*)\" should contain \"([^\"]*)\"$": [ + + ], + "^the stdout from \"([^\"]*)\" should not contain \"([^\"]*)\"$": [ + + ], + "^the stderr from \"([^\"]*)\" should contain \"([^\"]*)\"$": [ + + ], + "^the stderr from \"([^\"]*)\" should not contain \"([^\"]*)\"$": [ + + ], + "^the file \"([^\"]*)\" should not exist$": [ + + ], + "^the following files should exist:$": [ + + ], + "^the following files should not exist:$": [ + + ], + "^a file named \"([^\"]*)\" should exist$": [ + + ], + "^a file named \"([^\"]*)\" should not exist$": [ + + ], + "^a (\\d+) byte file named \"([^\"]*)\" should exist$": [ + + ], + "^the following directories should exist:$": [ + + ], + "^the following directories should not exist:$": [ + + ], + "^a directory named \"([^\"]*)\" should exist$": [ + + ], + "^a directory named \"([^\"]*)\" should not exist$": [ + + ], + "^the file \"([^\"]*)\" should contain \"([^\"]*)\"$": [ + + ], + "^the file \"([^\"]*)\" should not contain \"([^\"]*)\"$": [ + + ], + "^the file \"([^\"]*)\" should contain exactly:$": [ + + ], + "^the file \"([^\"]*)\" should match \\/([^\\/]*)\\/$": [ + + ], + "^the file \"([^\"]*)\" should not match \\/([^\\/]*)\\/$": [ + + ], + "^a scenario \"([^\"]*)\" with:$": [ + "a scenario \"Add three numbers\" with:", + "a scenario \"Add two numbers\" with:", + "a scenario \"Basic Arithmetic\" with:", + "a scenario \"Calculate PI\" with:", + "a scenario \"Simple math\" with:", + "a scenario \"Too simple math\" with:" + ], + "^the following feature:$": [ + "the following feature:" + ], + "^the step \"([^\"]*)\" has a passing mapping$": [ + "the step \"I add 4 and 5\" has a passing mapping", + "the step \"the result is 9\" has a passing mapping" + ], + "^the step \"([^\"]*)\" has a pending mapping$": [ + "the step \"I add 4 and 5\" has a pending mapping" + ], + "^the step \"([^\"]*)\" has a failing mapping$": [ + "the step \"I add 4 and 5\" has a failing mapping" + ], + "^Cucumber executes the scenario \"([^\"]*)\"$": [ + "Cucumber executes the scenario \"Basic Arithmetic\"" + ], + "^Cucumber runs the feature$": [ + "Cucumber runs the feature" + ], + "^Cucumber runs the scenario with steps for a calculator$": [ + "Cucumber runs the scenario with steps for a calculator" + ], + "^the scenario passes$": [ + "the scenario passes" + ], + "^the scenario fails$": [ + "the scenario fails" + ], + "^the scenario is pending$": [ + "the scenario is pending" + ], + "^the scenario is undefined$": [ + "the scenario is undefined" + ], + "^the step \"([^\"]*)\" is skipped$": [ + "the step \"the result is 9\" is skipped" + ], + "^the feature passes$": [ + "the feature passes" + ], + "^I run cucumber \"(.+)\"$": [ + "I run cucumber \"--format json features/doc_string.feature\"", + "I run cucumber \"--format json features/one_passing_one_failing.feature\"", + "I run cucumber \"-b --format json features/embed.feature\"", + "I run cucumber \"features/f.feature --format Ze::Formator\"", + "I run cucumber \"features/foo.feature\"", + "I run cucumber \"features/one_passing_one_failing.feature -r features -f rerun\"", + "I run cucumber \"features/sample.feature --tags ~@wip\"", + "I run cucumber \"features/sample.feature -r features --tags ~@wip\"" + ], + "^it should (pass|fail) with JSON:$": [ + "it should fail with JSON:", + "it should pass with JSON:" + ], + "^a directory without standard Cucumber project directory structure$": [ + "a directory without standard Cucumber project directory structure" + ], + "^a scenario with a step that looks like this:$": [ + "a scenario with a step that looks like this:" + ], + "^a step definition that looks like this:$": [ + "a step definition that looks like this:" + ], + "^I run the feature with the (\\w+) formatter$": [ + "I run the feature with the progress formatter" + ], + "^I am running spork in the background$": [ + "I am running spork in the background" + ], + "^jeg drikker en \"([^\"]*)\"$": [ + "jeg drikker en \"øl\"" + ], + "^skal de andre si \"([^\"]*)\"$": [ + "skal de andre si \"skål\"" + ] +} \ No newline at end of file diff --git a/lib/cucumber/ast/feature.rb b/lib/cucumber/ast/feature.rb index 9df0b484698..385be7383f1 100644 --- a/lib/cucumber/ast/feature.rb +++ b/lib/cucumber/ast/feature.rb @@ -8,7 +8,7 @@ class Feature #:nodoc: attr_accessor :language attr_writer :features, :background - attr_reader :file + attr_reader :file, :feature_elements def initialize(background, comment, tags, keyword, title, description, feature_elements) @background, @comment, @tags, @keyword, @title, @description, @feature_elements = background, comment, tags, keyword, title, description, feature_elements diff --git a/lib/cucumber/cli/configuration.rb b/lib/cucumber/cli/configuration.rb index bd7751d2dc6..d0673965621 100644 --- a/lib/cucumber/cli/configuration.rb +++ b/lib/cucumber/cli/configuration.rb @@ -64,6 +64,10 @@ def expand? @options[:expand] end + def dotcucumber + @options[:dotcucumber] + end + def build_tree_walker(step_mother) Ast::TreeWalker.new(step_mother, formatters(step_mother), self) end diff --git a/lib/cucumber/cli/main.rb b/lib/cucumber/cli/main.rb index 976481722e5..e13f9102d04 100644 --- a/lib/cucumber/cli/main.rb +++ b/lib/cucumber/cli/main.rb @@ -41,6 +41,7 @@ def execute!(existing_runtime = nil) end runtime.run! + runtime.write_stepdefs_json runtime.results.failure? rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e @error_stream.puts e.message diff --git a/lib/cucumber/cli/options.rb b/lib/cucumber/cli/options.rb index 2e56c04ea3a..5324fd6bf84 100644 --- a/lib/cucumber/cli/options.rb +++ b/lib/cucumber/cli/options.rb @@ -271,6 +271,9 @@ def parse!(args) opts.on("--port PORT", "Specify DRb port. Ignored without --drb") do |port| @options[:drb_port] = port end + opts.on("--dotcucumber DIR", "Write metadata to DIR") do |dir| + @options[:dotcucumber] = dir + end opts.on_tail("--version", "Show version.") do @out_stream.puts Cucumber::VERSION Kernel.exit(0) diff --git a/lib/cucumber/runtime.rb b/lib/cucumber/runtime.rb index a37dfa95107..23bb7a36039 100644 --- a/lib/cucumber/runtime.rb +++ b/lib/cucumber/runtime.rb @@ -1,3 +1,4 @@ +require 'fileutils' require 'gherkin/rubify' require 'gherkin/i18n' require 'cucumber/configuration' @@ -118,6 +119,32 @@ def unknown_programming_language? @support_code.unknown_programming_language? end + def write_stepdefs_json + if(@configuration.dotcucumber) + stepdefs = {} + @support_code.step_definitions.sort{|a,b| a.to_hash['source'] <=> a.to_hash['source']}.each do |stepdef| + steps = [] + features.each do |feature| + feature.feature_elements.each do |feature_element| + feature_element.raw_steps.each do |step| + if(stepdef.arguments_from(step.name)) + steps << step.name + end + end + end + end + regexp = stepdef.to_hash['source'] + stepdefs[regexp] = steps.uniq.sort + end + if !File.directory?(@configuration.dotcucumber) + FileUtils.mkdir_p(@configuration.dotcucumber) + end + File.open(File.join(@configuration.dotcucumber, 'stepdefs.json'), 'w') do |io| + io.write(JSON.pretty_generate(stepdefs)) + end + end + end + private def fire_after_configuration_hook #:nodoc @@ -125,11 +152,11 @@ def fire_after_configuration_hook #:nodoc end def features - loader = Runtime::FeaturesLoader.new( + @loader ||= Runtime::FeaturesLoader.new( @configuration.feature_files, @configuration.filters, @configuration.tag_expression) - loader.features + @loader.features end def load_step_definitions diff --git a/spec/cucumber/cli/main_spec.rb b/spec/cucumber/cli/main_spec.rb index 9a9333be36d..2358a5e1a76 100644 --- a/spec/cucumber/cli/main_spec.rb +++ b/spec/cucumber/cli/main_spec.rb @@ -95,7 +95,7 @@ def do_execute context "--drb" do before(:each) do - @configuration = mock('Configuration', :drb? => true).as_null_object + @configuration = mock('Configuration', :drb? => true, :dotcucumber => false).as_null_object Configuration.stub!(:new).and_return(@configuration) @args = ['features']