cucumber 7.1.0 → 8.0.0.rc.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +79 -1
- data/CONTRIBUTING.md +2 -6
- data/README.md +4 -7
- data/lib/autotest/cucumber_mixin.rb +5 -2
- data/lib/autotest/discover.rb +3 -2
- data/lib/cucumber/cli/configuration.rb +4 -1
- data/lib/cucumber/cli/main.rb +4 -3
- data/lib/cucumber/cli/options.rb +8 -2
- data/lib/cucumber/cli/profile_loader.rb +1 -5
- data/lib/cucumber/cli/rerun_file.rb +1 -1
- data/lib/cucumber/configuration.rb +5 -4
- data/lib/cucumber/constantize.rb +1 -1
- data/lib/cucumber/deprecate.rb +2 -1
- data/lib/cucumber/errors.rb +1 -1
- data/lib/cucumber/events/hook_test_step_created.rb +1 -2
- data/lib/cucumber/events/step_activated.rb +0 -6
- data/lib/cucumber/events/step_definition_registered.rb +0 -5
- data/lib/cucumber/events/test_case_created.rb +1 -2
- data/lib/cucumber/events/test_run_finished.rb +2 -1
- data/lib/cucumber/events/test_step_created.rb +1 -2
- data/lib/cucumber/events/undefined_parameter_type.rb +1 -2
- data/lib/cucumber/events.rb +1 -1
- data/lib/cucumber/file_specs.rb +2 -1
- data/lib/cucumber/filters/activate_steps.rb +1 -0
- data/lib/cucumber/filters/tag_limits/verifier.rb +1 -3
- data/lib/cucumber/filters/tag_limits.rb +1 -3
- data/lib/cucumber/formatter/ansicolor.rb +63 -63
- data/lib/cucumber/formatter/ast_lookup.rb +2 -2
- data/lib/cucumber/formatter/backtrace_filter.rb +1 -1
- data/lib/cucumber/formatter/console.rb +10 -2
- data/lib/cucumber/formatter/console_issues.rb +6 -1
- data/lib/cucumber/formatter/duration_extractor.rb +1 -0
- data/lib/cucumber/formatter/errors.rb +1 -0
- data/lib/cucumber/formatter/fanout.rb +1 -1
- data/lib/cucumber/formatter/http_io.rb +6 -1
- data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
- data/lib/cucumber/formatter/io.rb +3 -1
- data/lib/cucumber/formatter/json.rb +8 -6
- data/lib/cucumber/formatter/junit.rb +6 -3
- data/lib/cucumber/formatter/message_builder.rb +3 -2
- data/lib/cucumber/formatter/pretty.rb +15 -5
- data/lib/cucumber/formatter/progress.rb +1 -0
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +1 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +2 -0
- data/lib/cucumber/formatter/rerun.rb +2 -0
- data/lib/cucumber/formatter/summary.rb +1 -0
- data/lib/cucumber/formatter/unicode.rb +4 -4
- data/lib/cucumber/formatter/usage.rb +3 -3
- data/lib/cucumber/gherkin/data_table_parser.rb +1 -0
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +2 -2
- data/lib/cucumber/glue/dsl.rb +4 -9
- data/lib/cucumber/glue/hook.rb +2 -1
- data/lib/cucumber/glue/invoke_in_world.rb +4 -4
- data/lib/cucumber/glue/proto_world.rb +10 -9
- data/lib/cucumber/glue/registry_and_more.rb +4 -18
- data/lib/cucumber/glue/step_definition.rb +6 -3
- data/lib/cucumber/hooks.rb +1 -0
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -1
- data/lib/cucumber/multiline_argument/data_table.rb +58 -71
- data/lib/cucumber/platform.rb +2 -2
- data/lib/cucumber/rake/task.rb +10 -7
- data/lib/cucumber/rspec/disable_option_parser.rb +6 -3
- data/lib/cucumber/running_test_case.rb +1 -0
- data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
- data/lib/cucumber/runtime/support_code.rb +3 -0
- data/lib/cucumber/runtime/user_interface.rb +5 -4
- data/lib/cucumber/runtime.rb +21 -37
- data/lib/cucumber/step_match.rb +5 -3
- data/lib/cucumber/step_match_search.rb +3 -2
- data/lib/cucumber/term/ansicolor.rb +74 -50
- data/lib/cucumber/term/banner.rb +1 -0
- data/lib/cucumber/version +1 -1
- data/lib/cucumber.rb +2 -1
- data/lib/simplecov_setup.rb +1 -1
- metadata +74 -73
| @@ -3,21 +3,48 @@ | |
| 3 3 | 
             
            require 'cucumber/platform'
         | 
| 4 4 | 
             
            require 'cucumber/term/ansicolor'
         | 
| 5 5 |  | 
| 6 | 
            -
            Cucumber::Term::ANSIColor.coloring = false if  | 
| 6 | 
            +
            Cucumber::Term::ANSIColor.coloring = false if !$stdout.tty? && !ENV.key?('AUTOTEST')
         | 
| 7 7 |  | 
| 8 8 | 
             
            module Cucumber
         | 
| 9 9 | 
             
              module Formatter
         | 
| 10 | 
            -
                #  | 
| 11 | 
            -
                # | 
| 12 | 
            -
                #  | 
| 13 | 
            -
                #  | 
| 14 | 
            -
                # | 
| 10 | 
            +
                # This module allows to format cucumber related outputs using ANSI escape sequences.
         | 
| 11 | 
            +
                #
         | 
| 12 | 
            +
                # For example, it provides a `passed` method which returns the string with
         | 
| 13 | 
            +
                # the ANSI escape sequence to format it green per default.
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # To use this, include or extend it in your class.
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                # Example:
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                #   require 'cucumber/formatter/ansicolor'
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                #   class MyFormatter
         | 
| 22 | 
            +
                #     extend Cucumber::Term::ANSIColor
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                #     def on_test_step_finished(event)
         | 
| 25 | 
            +
                #       $stdout.puts undefined(event.test_step) if event.result.undefined?
         | 
| 26 | 
            +
                #       $stdout.puts passed(event.test_step) if event.result.passed?
         | 
| 27 | 
            +
                #     end
         | 
| 28 | 
            +
                #   end
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                # This module also allows the user to customize the format of cucumber outputs
         | 
| 31 | 
            +
                # using environment variables.
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                # For instance, if your shell has a black background and a green font (like the
         | 
| 34 | 
            +
                # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
         | 
| 35 | 
            +
                # steps to be white instead of green.
         | 
| 36 | 
            +
                #
         | 
| 37 | 
            +
                # Example:
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                #   export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
         | 
| 15 40 | 
             
                #
         | 
| 16 41 | 
             
                # The colours that you can change are:
         | 
| 17 42 | 
             
                #
         | 
| 18 43 | 
             
                # * <tt>undefined</tt>     - defaults to <tt>yellow</tt>
         | 
| 19 44 | 
             
                # * <tt>pending</tt>       - defaults to <tt>yellow</tt>
         | 
| 20 45 | 
             
                # * <tt>pending_param</tt> - defaults to <tt>yellow,bold</tt>
         | 
| 46 | 
            +
                # * <tt>flaky</tt>         - defaults to <tt>yellow</tt>
         | 
| 47 | 
            +
                # * <tt>flaky_param</tt>   - defaults to <tt>yellow,bold</tt>
         | 
| 21 48 | 
             
                # * <tt>failed</tt>        - defaults to <tt>red</tt>
         | 
| 22 49 | 
             
                # * <tt>failed_param</tt>  - defaults to <tt>red,bold</tt>
         | 
| 23 50 | 
             
                # * <tt>passed</tt>        - defaults to <tt>green</tt>
         | 
| @@ -29,26 +56,18 @@ module Cucumber | |
| 29 56 | 
             
                # * <tt>comment</tt>       - defaults to <tt>grey</tt>
         | 
| 30 57 | 
             
                # * <tt>tag</tt>           - defaults to <tt>cyan</tt>
         | 
| 31 58 | 
             
                #
         | 
| 32 | 
            -
                # For instance, if your shell has a black background and a green font (like the
         | 
| 33 | 
            -
                # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
         | 
| 34 | 
            -
                # steps to be white instead of green.
         | 
| 35 | 
            -
                #
         | 
| 36 | 
            -
                # Although not listed, you can also use <tt>grey</tt>.
         | 
| 37 | 
            -
                #
         | 
| 38 | 
            -
                # Examples: (On Windows, use SET instead of export.)
         | 
| 39 | 
            -
                #
         | 
| 40 | 
            -
                #   export CUCUMBER_COLORS="passed=white"
         | 
| 41 | 
            -
                #   export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
         | 
| 42 | 
            -
                #
         | 
| 43 59 | 
             
                # To see what colours and effects are available, just run this in your shell:
         | 
| 44 60 | 
             
                #
         | 
| 45 | 
            -
                #   ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
         | 
| 61 | 
            +
                #   ruby -e "require 'rubygems'; require 'cucumber/term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
         | 
| 46 62 | 
             
                #
         | 
| 47 63 | 
             
                module ANSIColor
         | 
| 48 64 | 
             
                  include Cucumber::Term::ANSIColor
         | 
| 49 65 |  | 
| 66 | 
            +
                  # :stopdoc:
         | 
| 50 67 | 
             
                  ALIASES = Hash.new do |h, k|
         | 
| 51 | 
            -
                     | 
| 68 | 
            +
                    next unless k.to_s =~ /(.*)_param/
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    "#{h[Regexp.last_match(1)]},bold"
         | 
| 52 71 | 
             
                  end.merge(
         | 
| 53 72 | 
             
                    'undefined' => 'yellow',
         | 
| 54 73 | 
             
                    'pending'   => 'yellow',
         | 
| @@ -60,15 +79,22 @@ module Cucumber | |
| 60 79 | 
             
                    'comment'   => 'grey',
         | 
| 61 80 | 
             
                    'tag'       => 'cyan'
         | 
| 62 81 | 
             
                  )
         | 
| 82 | 
            +
                  # :startdoc:
         | 
| 63 83 |  | 
| 64 | 
            -
                   | 
| 65 | 
            -
             | 
| 84 | 
            +
                  # Apply the custom color scheme
         | 
| 85 | 
            +
                  #
         | 
| 86 | 
            +
                  # example:
         | 
| 87 | 
            +
                  #
         | 
| 88 | 
            +
                  #   apply_custom_colors('passed=white')
         | 
| 89 | 
            +
                  def apply_custom_colors(colors)
         | 
| 90 | 
            +
                    colors.split(':').each do |pair|
         | 
| 66 91 | 
             
                      a = pair.split('=')
         | 
| 67 92 | 
             
                      ALIASES[a[0]] = a[1]
         | 
| 68 93 | 
             
                    end
         | 
| 69 94 | 
             
                  end
         | 
| 95 | 
            +
                  apply_custom_colors(ENV['CUCUMBER_COLORS']) if ENV['CUCUMBER_COLORS']
         | 
| 70 96 |  | 
| 71 | 
            -
                  #  | 
| 97 | 
            +
                  # Define the color-named methods required by Term::ANSIColor.
         | 
| 72 98 | 
             
                  #
         | 
| 73 99 | 
             
                  # Examples:
         | 
| 74 100 | 
             
                  #
         | 
| @@ -80,53 +106,18 @@ module Cucumber | |
| 80 106 | 
             
                  #     red(bold(string, &proc)) + red
         | 
| 81 107 | 
             
                  #   end
         | 
| 82 108 | 
             
                  ALIASES.each_key do |method_name|
         | 
| 83 | 
            -
                    next if method_name | 
| 84 | 
            -
                    code = <<-COLOR
         | 
| 85 | 
            -
                      def #{method_name}(string=nil, &proc)
         | 
| 86 | 
            -
                        #{ALIASES[method_name].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name].split(',').length}
         | 
| 87 | 
            -
                      end
         | 
| 88 | 
            -
                      # This resets the colour to the non-param colour
         | 
| 89 | 
            -
                      def #{method_name}_param(string=nil, &proc)
         | 
| 90 | 
            -
                        #{ALIASES[method_name + '_param'].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name + '_param'].split(',').length} + #{ALIASES[method_name].split(',').join(' + ')}
         | 
| 91 | 
            -
                      end
         | 
| 92 | 
            -
                    COLOR
         | 
| 93 | 
            -
                    eval(code) # rubocop:disable Security/Eval
         | 
| 94 | 
            -
                  end
         | 
| 109 | 
            +
                    next if method_name.end_with?('_param')
         | 
| 95 110 |  | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
                    require 'terminfo'
         | 
| 99 | 
            -
                    case TermInfo.default_object.tigetnum('colors')
         | 
| 100 | 
            -
                    when 0
         | 
| 101 | 
            -
                      raise "Your terminal doesn't support colours."
         | 
| 102 | 
            -
                    when 1
         | 
| 103 | 
            -
                      ::Cucumber::Term::ANSIColor.coloring = false
         | 
| 104 | 
            -
                      alias_method :grey, :white
         | 
| 105 | 
            -
                    when 2..8
         | 
| 106 | 
            -
                      alias_method :grey, :white # rubocop:disable Lint/DuplicateMethods
         | 
| 107 | 
            -
                    else
         | 
| 108 | 
            -
                      define_real_grey
         | 
| 109 | 
            -
                    end
         | 
| 110 | 
            -
                  rescue Exception => e # rubocop:disable Lint/RescueException
         | 
| 111 | 
            -
                    if e.class.name == 'TermInfo::TermInfoError'
         | 
| 112 | 
            -
                      STDERR.puts '*** WARNING ***'
         | 
| 113 | 
            -
                      STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
         | 
| 114 | 
            -
                      STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
         | 
| 115 | 
            -
                      STDERR.puts "\n"
         | 
| 116 | 
            -
                      alias_method :grey, :white
         | 
| 117 | 
            -
                    else
         | 
| 118 | 
            -
                      define_real_grey
         | 
| 111 | 
            +
                    define_method(method_name) do |text = nil, &proc|
         | 
| 112 | 
            +
                      apply_styles(ALIASES[method_name], text, &proc)
         | 
| 119 113 | 
             
                    end
         | 
| 120 | 
            -
                  end
         | 
| 121 114 |  | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
                      ::Cucumber::Term::ANSIColor.coloring? ? "\e[90m#{string}\e[0m" : string
         | 
| 115 | 
            +
                    define_method("#{method_name}_param") do |text = nil, &proc|
         | 
| 116 | 
            +
                      apply_styles(ALIASES["#{method_name}_param"], text, &proc) + apply_styles(ALIASES[method_name])
         | 
| 125 117 | 
             
                    end
         | 
| 126 118 | 
             
                  end
         | 
| 127 119 |  | 
| 128 | 
            -
                   | 
| 129 | 
            -
             | 
| 120 | 
            +
                  # :stopdoc:
         | 
| 130 121 | 
             
                  def cukes(n)
         | 
| 131 122 | 
             
                    ('(::) ' * n).strip
         | 
| 132 123 | 
             
                  end
         | 
| @@ -142,6 +133,15 @@ module Cucumber | |
| 142 133 | 
             
                  def yellow_cukes(n)
         | 
| 143 134 | 
             
                    blink(yellow(cukes(n)))
         | 
| 144 135 | 
             
                  end
         | 
| 136 | 
            +
                  # :startdoc:
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                  private
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  def apply_styles(styles, text = nil, &proc)
         | 
| 141 | 
            +
                    styles.split(',').reverse.reduce(text) do |result, method_name|
         | 
| 142 | 
            +
                      send(method_name, result, &proc)
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                  end
         | 
| 145 145 | 
             
                end
         | 
| 146 146 | 
             
              end
         | 
| 147 147 | 
             
            end
         | 
| @@ -45,11 +45,11 @@ module Cucumber | |
| 45 45 | 
             
                        break
         | 
| 46 46 | 
             
                      end
         | 
| 47 47 | 
             
                      break if node.previous_node.nil?
         | 
| 48 | 
            +
             | 
| 48 49 | 
             
                      node = node.previous_node
         | 
| 49 50 | 
             
                    end
         | 
| 50 51 | 
             
                    keyword = dialect.given_keywords.reject { |kw| kw == '* ' }[0] if keyword.nil?
         | 
| 51 | 
            -
                     | 
| 52 | 
            -
                    keyword
         | 
| 52 | 
            +
                    Cucumber::Gherkin::I18n.code_keyword_for(keyword)
         | 
| 53 53 | 
             
                  end
         | 
| 54 54 |  | 
| 55 55 | 
             
                  ScenarioSource = Struct.new(:type, :scenario)
         | 
| @@ -33,7 +33,7 @@ module Cucumber | |
| 33 33 | 
             
                  def exception
         | 
| 34 34 | 
             
                    return @exception if ::Cucumber.use_full_backtrace
         | 
| 35 35 |  | 
| 36 | 
            -
                    pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m | 
| 36 | 
            +
                    pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m
         | 
| 37 37 | 
             
                    backtrace = @exception.backtrace.map { |line| line.gsub(pwd_pattern, './') }
         | 
| 38 38 |  | 
| 39 39 | 
             
                    filtered = (backtrace || []).reject do |line|
         | 
| @@ -34,7 +34,7 @@ module Cucumber | |
| 34 34 |  | 
| 35 35 | 
             
                  def format_step(keyword, step_match, status, source_indent)
         | 
| 36 36 | 
             
                    comment = if source_indent
         | 
| 37 | 
            -
                                c = indent( | 
| 37 | 
            +
                                c = indent("# #{step_match.location}", source_indent)
         | 
| 38 38 | 
             
                                format_string(c, :comment)
         | 
| 39 39 | 
             
                              else
         | 
| 40 40 | 
             
                                ''
         | 
| @@ -109,7 +109,10 @@ module Cucumber | |
| 109 109 | 
             
                  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
         | 
| 110 110 | 
             
                  def linebreaks(msg, max)
         | 
| 111 111 | 
             
                    return msg unless max && max > 0
         | 
| 112 | 
            -
             | 
| 112 | 
            +
             | 
| 113 | 
            +
                    msg.gsub(/.{1,#{max}}(?:\s|\Z)/) do
         | 
| 114 | 
            +
                      (Regexp.last_match(0) + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n")
         | 
| 115 | 
            +
                    end.rstrip
         | 
| 113 116 | 
             
                  end
         | 
| 114 117 |  | 
| 115 118 | 
             
                  def collect_snippet_data(test_step, ast_lookup)
         | 
| @@ -150,6 +153,7 @@ module Cucumber | |
| 150 153 |  | 
| 151 154 | 
             
                  def print_passing_wip(config, passed_test_cases, ast_lookup)
         | 
| 152 155 | 
             
                    return unless config.wip?
         | 
| 156 | 
            +
             | 
| 153 157 | 
             
                    messages = passed_test_cases.map do |test_case|
         | 
| 154 158 | 
             
                      scenario_source = ast_lookup.scenario_source(test_case)
         | 
| 155 159 | 
             
                      keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
         | 
| @@ -170,6 +174,7 @@ module Cucumber | |
| 170 174 | 
             
                  def attach(src, media_type)
         | 
| 171 175 | 
             
                    return unless media_type == 'text/x.cucumber.log+plain'
         | 
| 172 176 | 
             
                    return unless @io
         | 
| 177 | 
            +
             | 
| 173 178 | 
             
                    @io.puts
         | 
| 174 179 | 
             
                    @io.puts(format_string(src, :tag))
         | 
| 175 180 | 
             
                    @io.flush
         | 
| @@ -177,6 +182,7 @@ module Cucumber | |
| 177 182 |  | 
| 178 183 | 
             
                  def print_profile_information
         | 
| 179 184 | 
             
                    return if @options[:skip_profile_information] || @options[:profiles].nil? || @options[:profiles].empty?
         | 
| 185 | 
            +
             | 
| 180 186 | 
             
                    do_print_profile_information(@options[:profiles])
         | 
| 181 187 | 
             
                  end
         | 
| 182 188 |  | 
| @@ -224,6 +230,7 @@ module Cucumber | |
| 224 230 | 
             
                    key = keys.join('_').to_sym
         | 
| 225 231 | 
             
                    fmt = FORMATS[key]
         | 
| 226 232 | 
             
                    raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
         | 
| 233 | 
            +
             | 
| 227 234 | 
             
                    fmt
         | 
| 228 235 | 
             
                  end
         | 
| 229 236 |  | 
| @@ -246,6 +253,7 @@ module Cucumber | |
| 246 253 |  | 
| 247 254 | 
             
                  class SnippetData
         | 
| 248 255 | 
             
                    attr_reader :actual_keyword, :step
         | 
| 256 | 
            +
             | 
| 249 257 | 
             
                    def initialize(actual_keyword, step)
         | 
| 250 258 | 
             
                      @actual_keyword = actual_keyword
         | 
| 251 259 | 
             
                      @step = step
         | 
| @@ -23,6 +23,7 @@ module Cucumber | |
| 23 23 |  | 
| 24 24 | 
             
                  def to_s
         | 
| 25 25 | 
             
                    return if @issues.empty?
         | 
| 26 | 
            +
             | 
| 26 27 | 
             
                    result = Core::Test::Result::TYPES.map { |type| scenario_listing(type, @issues[type]) }
         | 
| 27 28 | 
             
                    result.flatten.join("\n")
         | 
| 28 29 | 
             
                  end
         | 
| @@ -35,6 +36,7 @@ module Cucumber | |
| 35 36 |  | 
| 36 37 | 
             
                  def scenario_listing(type, test_cases)
         | 
| 37 38 | 
             
                    return [] if test_cases.empty?
         | 
| 39 | 
            +
             | 
| 38 40 | 
             
                    [format_string("#{type_heading(type)} Scenarios:", type)] + test_cases.map do |test_case|
         | 
| 39 41 | 
             
                      scenario_source = @ast_lookup.scenario_source(test_case)
         | 
| 40 42 | 
             
                      keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
         | 
| @@ -54,7 +56,10 @@ module Cucumber | |
| 54 56 |  | 
| 55 57 | 
             
                  def profiles_string
         | 
| 56 58 | 
             
                    return if @config.custom_profiles.empty?
         | 
| 57 | 
            -
             | 
| 59 | 
            +
             | 
| 60 | 
            +
                    profiles = @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ')
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    "#{profiles} "
         | 
| 58 63 | 
             
                  end
         | 
| 59 64 | 
             
                end
         | 
| 60 65 | 
             
              end
         | 
| @@ -21,7 +21,7 @@ module Cucumber | |
| 21 21 | 
             
                  end
         | 
| 22 22 |  | 
| 23 23 | 
             
                  def respond_to_missing?(name, include_private = false)
         | 
| 24 | 
            -
                    recipients.any? { |recipient| recipient.respond_to?(name, include_private) }
         | 
| 24 | 
            +
                    recipients.any? { |recipient| recipient.respond_to?(name, include_private) } || super(name, include_private)
         | 
| 25 25 | 
             
                  end
         | 
| 26 26 | 
             
                end
         | 
| 27 27 | 
             
              end
         | 
| @@ -35,6 +35,7 @@ module Cucumber | |
| 35 35 | 
             
                        headers = headers.merge(parse_header(header_arg))
         | 
| 36 36 | 
             
                      else
         | 
| 37 37 | 
             
                        raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
         | 
| 38 | 
            +
             | 
| 38 39 | 
             
                        url = arg
         | 
| 39 40 | 
             
                      end
         | 
| 40 41 | 
             
                    end
         | 
| @@ -49,12 +50,14 @@ module Cucumber | |
| 49 50 |  | 
| 50 51 | 
             
                  def self.remove_arg_for(args, arg)
         | 
| 51 52 | 
             
                    return args.shift unless args.empty?
         | 
| 53 | 
            +
             | 
| 52 54 | 
             
                    raise StandardError, "Missing argument for #{arg}"
         | 
| 53 55 | 
             
                  end
         | 
| 54 56 |  | 
| 55 57 | 
             
                  def self.parse_header(header_arg)
         | 
| 56 58 | 
             
                    parts = header_arg.split(':', 2)
         | 
| 57 59 | 
             
                    raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
         | 
| 60 | 
            +
             | 
| 58 61 | 
             
                    { parts[0].strip => parts[1].strip }
         | 
| 59 62 | 
             
                  end
         | 
| 60 63 | 
             
                end
         | 
| @@ -76,6 +79,7 @@ module Cucumber | |
| 76 79 | 
             
                    @reporter.report(response.body)
         | 
| 77 80 | 
             
                    @write_io.close
         | 
| 78 81 | 
             
                    return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
         | 
| 82 | 
            +
             | 
| 79 83 | 
             
                    raise StandardError, "request to #{uri} failed with status #{response.code}"
         | 
| 80 84 | 
             
                  end
         | 
| 81 85 |  | 
| @@ -98,6 +102,7 @@ module Cucumber | |
| 98 102 | 
             
                    http = build_client(uri, @https_verify_mode)
         | 
| 99 103 |  | 
| 100 104 | 
             
                    raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
         | 
| 105 | 
            +
             | 
| 101 106 | 
             
                    req = build_request(
         | 
| 102 107 | 
             
                      uri,
         | 
| 103 108 | 
             
                      method,
         | 
| @@ -126,7 +131,7 @@ module Cucumber | |
| 126 131 | 
             
                  end
         | 
| 127 132 |  | 
| 128 133 | 
             
                  def build_request(uri, method, headers)
         | 
| 129 | 
            -
                    method_class_name = "#{method[0].upcase}#{method[1 | 
| 134 | 
            +
                    method_class_name = "#{method[0].upcase}#{method[1..].downcase}"
         | 
| 130 135 | 
             
                    req = Net::HTTP.const_get(method_class_name).new(uri)
         | 
| 131 136 | 
             
                    headers.each do |header, value|
         | 
| 132 137 | 
             
                      req[header] = value
         | 
| @@ -57,19 +57,21 @@ module Cucumber | |
| 57 57 | 
             
                  end
         | 
| 58 58 |  | 
| 59 59 | 
             
                  def url?(path_or_url_or_io)
         | 
| 60 | 
            -
                    path_or_url_or_io.match( | 
| 60 | 
            +
                    path_or_url_or_io.match(/^https?:\/\//)
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 63 | 
             
                  def ensure_file(path, name)
         | 
| 64 64 | 
             
                    raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
         | 
| 65 65 | 
             
                    raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
         | 
| 66 66 | 
             
                    raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
         | 
| 67 | 
            +
             | 
| 67 68 | 
             
                    ensure_io(path, nil)
         | 
| 68 69 | 
             
                  end
         | 
| 69 70 |  | 
| 70 71 | 
             
                  def ensure_dir(path, name)
         | 
| 71 72 | 
             
                    raise "You *must* specify --out DIR for the #{name} formatter" unless String == path.class
         | 
| 72 73 | 
             
                    raise "I can't write #{name} reports to a file - it has to be a directory" if File.file?(path)
         | 
| 74 | 
            +
             | 
| 73 75 | 
             
                    FileUtils.mkdir_p(path) unless File.directory?(path)
         | 
| 74 76 | 
             
                    File.absolute_path path
         | 
| 75 77 | 
             
                  end
         | 
| @@ -68,6 +68,7 @@ module Cucumber | |
| 68 68 | 
             
                    test_step, result = *event.attributes
         | 
| 69 69 | 
             
                    result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
         | 
| 70 70 | 
             
                    return if internal_hook?(test_step)
         | 
| 71 | 
            +
             | 
| 71 72 | 
             
                    add_match_and_result(test_step, result)
         | 
| 72 73 | 
             
                    @any_step_failed = true if result.failed?
         | 
| 73 74 | 
             
                  end
         | 
| @@ -81,7 +82,7 @@ module Cucumber | |
| 81 82 | 
             
                  end
         | 
| 82 83 |  | 
| 83 84 | 
             
                  def on_test_run_finished(_event)
         | 
| 84 | 
            -
                    @io.write(JSON. | 
| 85 | 
            +
                    @io.write(JSON.pretty_generate(@feature_hashes))
         | 
| 85 86 | 
             
                  end
         | 
| 86 87 |  | 
| 87 88 | 
             
                  def attach(src, mime_type)
         | 
| @@ -105,7 +106,7 @@ module Cucumber | |
| 105 106 | 
             
                  end
         | 
| 106 107 |  | 
| 107 108 | 
             
                  def first_step_after_background?(test_step)
         | 
| 108 | 
            -
                    @in_background && test_step.location.lines.max >= @test_case_hash[:line]
         | 
| 109 | 
            +
                    @in_background && test_step.location.file == @feature_hash[:uri] && test_step.location.lines.max >= @test_case_hash[:line]
         | 
| 109 110 | 
             
                  end
         | 
| 110 111 |  | 
| 111 112 | 
             
                  def internal_hook?(test_step)
         | 
| @@ -133,7 +134,7 @@ module Cucumber | |
| 133 134 | 
             
                    when 'AfterStep hook'
         | 
| 134 135 | 
             
                      after_step_hooks
         | 
| 135 136 | 
             
                    else
         | 
| 136 | 
            -
                      raise  | 
| 137 | 
            +
                      raise "Unknown hook type #{hook_step}"
         | 
| 137 138 | 
             
                    end
         | 
| 138 139 | 
             
                  end
         | 
| 139 140 |  | 
| @@ -175,15 +176,15 @@ module Cucumber | |
| 175 176 | 
             
                      name: test_step.text,
         | 
| 176 177 | 
             
                      line: test_step.location.lines.min
         | 
| 177 178 | 
             
                    }
         | 
| 178 | 
            -
                    step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string) unless step_source.doc_string.nil?
         | 
| 179 | 
            +
                    step_hash[:doc_string] = create_doc_string_hash(step_source.doc_string, test_step.multiline_arg.content) unless step_source.doc_string.nil?
         | 
| 179 180 | 
             
                    step_hash[:rows] = create_data_table_value(step_source.data_table) unless step_source.data_table.nil?
         | 
| 180 181 | 
             
                    step_hash
         | 
| 181 182 | 
             
                  end
         | 
| 182 183 |  | 
| 183 | 
            -
                  def create_doc_string_hash(doc_string)
         | 
| 184 | 
            +
                  def create_doc_string_hash(doc_string, doc_string_content)
         | 
| 184 185 | 
             
                    content_type = doc_string.media_type || ''
         | 
| 185 186 | 
             
                    {
         | 
| 186 | 
            -
                      value:  | 
| 187 | 
            +
                      value: doc_string_content,
         | 
| 187 188 | 
             
                      content_type: content_type,
         | 
| 188 189 | 
             
                      line: doc_string.location.line
         | 
| 189 190 | 
             
                    }
         | 
| @@ -259,6 +260,7 @@ module Cucumber | |
| 259 260 | 
             
                        line: feature.location.line
         | 
| 260 261 | 
             
                      }
         | 
| 261 262 | 
             
                      return if feature.tags.empty?
         | 
| 263 | 
            +
             | 
| 262 264 | 
             
                      @feature_hash[:tags] = create_tags_array_from_hash_array(feature.tags)
         | 
| 263 265 | 
             
                    end
         | 
| 264 266 |  | 
| @@ -84,6 +84,7 @@ module Cucumber | |
| 84 84 | 
             
                    uri = test_case.location.file
         | 
| 85 85 | 
             
                    feature = @ast_lookup.gherkin_document(uri).feature
         | 
| 86 86 | 
             
                    raise UnNamedFeatureError, uri if feature.name.empty?
         | 
| 87 | 
            +
             | 
| 87 88 | 
             
                    @current_feature_data = @features_data[uri]
         | 
| 88 89 | 
             
                    @current_feature_data[:uri] = uri unless @current_feature_data[:uri]
         | 
| 89 90 | 
             
                    @current_feature_data[:feature] = feature unless @current_feature_data[:feature]
         | 
| @@ -111,6 +112,7 @@ module Cucumber | |
| 111 112 | 
             
                    keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
         | 
| 112 113 | 
             
                    output = "#{keyword}: #{scenario}\n\n"
         | 
| 113 114 | 
             
                    return output if result.ok?(@config.strict)
         | 
| 115 | 
            +
             | 
| 114 116 | 
             
                    if scenario_source.type == :Scenario
         | 
| 115 117 | 
             
                      if @failing_test_step
         | 
| 116 118 | 
             
                        if @failing_test_step.hook?
         | 
| @@ -125,7 +127,7 @@ module Cucumber | |
| 125 127 | 
             
                    else
         | 
| 126 128 | 
             
                      output += "Example row: #{row_name}\n"
         | 
| 127 129 | 
             
                    end
         | 
| 128 | 
            -
                    output | 
| 130 | 
            +
                    "#{output}\nMessage:\n"
         | 
| 129 131 | 
             
                  end
         | 
| 130 132 |  | 
| 131 133 | 
             
                  def build_testcase(result, scenario_designation, output)
         | 
| @@ -191,7 +193,7 @@ module Cucumber | |
| 191 193 | 
             
                  end
         | 
| 192 194 |  | 
| 193 195 | 
             
                  def basename(feature_file)
         | 
| 194 | 
            -
                    File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature') | 
| 196 | 
            +
                    File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature')
         | 
| 195 197 | 
             
                  end
         | 
| 196 198 |  | 
| 197 199 | 
             
                  def write_file(feature_filename, data)
         | 
| @@ -228,13 +230,14 @@ module Cucumber | |
| 228 230 | 
             
                  end
         | 
| 229 231 |  | 
| 230 232 | 
             
                  def examples_table_row(row)
         | 
| 231 | 
            -
                    @row_name =  | 
| 233 | 
            +
                    @row_name = "| #{row.cells.map(&:value).join(' | ')} |"
         | 
| 232 234 | 
             
                    @name_suffix = " (outline example : #{@row_name})"
         | 
| 233 235 | 
             
                  end
         | 
| 234 236 | 
             
                end
         | 
| 235 237 |  | 
| 236 238 | 
             
                class ResultBuilder
         | 
| 237 239 | 
             
                  attr_reader :test_case_duration
         | 
| 240 | 
            +
             | 
| 238 241 | 
             
                  def initialize(result)
         | 
| 239 242 | 
             
                    @test_case_duration = 0
         | 
| 240 243 | 
             
                    result.describe_to(self)
         | 
| @@ -226,10 +226,11 @@ module Cucumber | |
| 226 226 | 
             
                    output_envelope(message)
         | 
| 227 227 | 
             
                  end
         | 
| 228 228 |  | 
| 229 | 
            -
                  def on_test_run_finished( | 
| 229 | 
            +
                  def on_test_run_finished(event)
         | 
| 230 230 | 
             
                    message = Cucumber::Messages::Envelope.new(
         | 
| 231 231 | 
             
                      test_run_finished: Cucumber::Messages::TestRunFinished.new(
         | 
| 232 | 
            -
                        timestamp: time_to_timestamp(Time.now)
         | 
| 232 | 
            +
                        timestamp: time_to_timestamp(Time.now),
         | 
| 233 | 
            +
                        success: event.success
         | 
| 233 234 | 
             
                      )
         | 
| 234 235 | 
             
                    )
         | 
| 235 236 |  | 
| @@ -24,11 +24,9 @@ module Cucumber | |
| 24 24 | 
             
                  include Console
         | 
| 25 25 | 
             
                  include Io
         | 
| 26 26 | 
             
                  include Cucumber::Gherkin::Formatter::Escaping
         | 
| 27 | 
            -
                  attr_reader :config, :options
         | 
| 27 | 
            +
                  attr_reader :config, :options, :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case, :in_scenario_outline, :print_background_steps
         | 
| 28 28 | 
             
                  private :config, :options
         | 
| 29 | 
            -
                  attr_reader :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
         | 
| 30 29 | 
             
                  private :current_feature_uri, :current_scenario_outline, :current_examples, :current_test_case
         | 
| 31 | 
            -
                  attr_reader :in_scenario_outline, :print_background_steps
         | 
| 32 30 | 
             
                  private :in_scenario_outline, :print_background_steps
         | 
| 33 31 |  | 
| 34 32 | 
             
                  def initialize(config)
         | 
| @@ -105,16 +103,19 @@ module Cucumber | |
| 105 103 |  | 
| 106 104 | 
             
                  def on_test_step_started(event)
         | 
| 107 105 | 
             
                    return if event.test_step.hook?
         | 
| 106 | 
            +
             | 
| 108 107 | 
             
                    print_step_header(current_test_case) if first_step_after_printing_background_steps?(event.test_step)
         | 
| 109 108 | 
             
                  end
         | 
| 110 109 |  | 
| 111 110 | 
             
                  def on_test_step_finished(event)
         | 
| 112 111 | 
             
                    collect_snippet_data(event.test_step, @ast_lookup) if event.result.undefined?
         | 
| 113 112 | 
             
                    return if in_scenario_outline && !options[:expand]
         | 
| 113 | 
            +
             | 
| 114 114 | 
             
                    exception_to_be_printed = find_exception_to_be_printed(event.result)
         | 
| 115 115 | 
             
                    print_step_data(event.test_step, event.result) if print_step_data?(event, exception_to_be_printed)
         | 
| 116 116 | 
             
                    print_step_output
         | 
| 117 117 | 
             
                    return unless exception_to_be_printed
         | 
| 118 | 
            +
             | 
| 118 119 | 
             
                    print_exception(exception_to_be_printed, event.result.to_sym, 6)
         | 
| 119 120 | 
             
                    @exceptions << exception_to_be_printed
         | 
| 120 121 | 
             
                  end
         | 
| @@ -127,6 +128,7 @@ module Cucumber | |
| 127 128 | 
             
                    else
         | 
| 128 129 | 
             
                      exception_to_be_printed = find_exception_to_be_printed(event.result)
         | 
| 129 130 | 
             
                      return unless exception_to_be_printed
         | 
| 131 | 
            +
             | 
| 130 132 | 
             
                      print_exception(exception_to_be_printed, event.result.to_sym, 6)
         | 
| 131 133 | 
             
                      @exceptions << exception_to_be_printed
         | 
| 132 134 | 
             
                    end
         | 
| @@ -140,6 +142,7 @@ module Cucumber | |
| 140 142 |  | 
| 141 143 | 
             
                  def attach(src, media_type)
         | 
| 142 144 | 
             
                    return unless media_type == 'text/x.cucumber.log+plain'
         | 
| 145 | 
            +
             | 
| 143 146 | 
             
                    @test_step_output.push src
         | 
| 144 147 | 
             
                  end
         | 
| 145 148 |  | 
| @@ -147,9 +150,11 @@ module Cucumber | |
| 147 150 |  | 
| 148 151 | 
             
                  def find_exception_to_be_printed(result)
         | 
| 149 152 | 
             
                    return nil if result.ok?(options[:strict])
         | 
| 153 | 
            +
             | 
| 150 154 | 
             
                    result = result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
         | 
| 151 155 | 
             
                    exception = result.failed? ? result.exception : result
         | 
| 152 156 | 
             
                    return nil if @exceptions.include?(exception)
         | 
| 157 | 
            +
             | 
| 153 158 | 
             
                    exception
         | 
| 154 159 | 
             
                  end
         | 
| 155 160 |  | 
| @@ -196,6 +201,7 @@ module Cucumber | |
| 196 201 | 
             
                  def feature_has_background?
         | 
| 197 202 | 
             
                    feature_children = gherkin_document.feature.children
         | 
| 198 203 | 
             
                    return false if feature_children.empty?
         | 
| 204 | 
            +
             | 
| 199 205 | 
             
                    !feature_children.first.background.nil?
         | 
| 200 206 | 
             
                  end
         | 
| 201 207 |  | 
| @@ -239,6 +245,7 @@ module Cucumber | |
| 239 245 | 
             
                  def first_step_after_printing_background_steps?(test_step)
         | 
| 240 246 | 
             
                    return false unless print_background_steps
         | 
| 241 247 | 
             
                    return false unless test_step.location.lines.max >= current_test_case.location.lines.max
         | 
| 248 | 
            +
             | 
| 242 249 | 
             
                    @print_background_steps = false
         | 
| 243 250 | 
             
                    true
         | 
| 244 251 | 
             
                  end
         | 
| @@ -262,7 +269,8 @@ module Cucumber | |
| 262 269 | 
             
                  def print_comments(up_to_line, indent_amount)
         | 
| 263 270 | 
             
                    comments = gherkin_document.comments
         | 
| 264 271 | 
             
                    return if comments.empty? || comments.length <= @next_comment_to_be_printed
         | 
| 265 | 
            -
             | 
| 272 | 
            +
             | 
| 273 | 
            +
                    comments[@next_comment_to_be_printed..].each do |comment|
         | 
| 266 274 | 
             
                      if comment.location.line <= up_to_line
         | 
| 267 275 | 
             
                        @io.puts(indent(format_string(comment.text.strip, :comment), indent_amount))
         | 
| 268 276 | 
             
                        @next_comment_to_be_printed += 1
         | 
| @@ -294,6 +302,7 @@ module Cucumber | |
| 294 302 |  | 
| 295 303 | 
             
                  def print_description(description)
         | 
| 296 304 | 
             
                    return unless description
         | 
| 305 | 
            +
             | 
| 297 306 | 
             
                    description.split("\n").each do |line|
         | 
| 298 307 | 
             
                      @io.puts(line)
         | 
| 299 308 | 
             
                    end
         | 
| @@ -398,6 +407,7 @@ module Cucumber | |
| 398 407 | 
             
                      end
         | 
| 399 408 | 
             
                      @io.puts
         | 
| 400 409 | 
             
                      next if options[:no_multiline]
         | 
| 410 | 
            +
             | 
| 401 411 | 
             
                      print_doc_string(step.doc_string.content, :skipped, 6) unless step.doc_string.nil?
         | 
| 402 412 | 
             
                      print_data_table(step.data_table, :skipped, 6) unless step.data_table.nil?
         | 
| 403 413 | 
             
                    end
         | 
| @@ -445,7 +455,7 @@ module Cucumber | |
| 445 455 | 
             
                    language = ::Gherkin::Dialect.for(language_code)
         | 
| 446 456 | 
             
                    scenario_keyword = language.scenario_keywords[0]
         | 
| 447 457 | 
             
                    row = scenario_source(test_case).row
         | 
| 448 | 
            -
                    expanded_name =  | 
| 458 | 
            +
                    expanded_name = "| #{row.cells.map(&:value).join(' | ')} |"
         | 
| 449 459 | 
             
                    @source_indent = calculate_source_indent_for_expanded_test_case(test_case, scenario_keyword, expanded_name)
         | 
| 450 460 | 
             
                    @io.puts
         | 
| 451 461 | 
             
                    print_keyword_name(scenario_keyword, expanded_name, 6, test_case.location)
         | 
| @@ -58,6 +58,7 @@ module Cucumber | |
| 58 58 | 
             
                    progress(result.to_sym) if !test_step.hook? || result.failed?
         | 
| 59 59 |  | 
| 60 60 | 
             
                    return if test_step.hook?
         | 
| 61 | 
            +
             | 
| 61 62 | 
             
                    collect_snippet_data(test_step, @ast_lookup) if result.undefined?
         | 
| 62 63 | 
             
                    @pending_step_matches << @matches[test_step.to_s] if result.pending?
         | 
| 63 64 | 
             
                    @failed_results << result if result.failed?
         | 
| @@ -13,6 +13,7 @@ module Cucumber | |
| 13 13 |  | 
| 14 14 | 
             
                    def hook_id(test_step)
         | 
| 15 15 | 
             
                      return @hook_id_by_test_step_id[test_step.id] if @hook_id_by_test_step_id.key?(test_step.id)
         | 
| 16 | 
            +
             | 
| 16 17 | 
             
                      raise TestStepUnknownError, "No hook found for #{test_step.id} }. Known: #{@hook_id_by_test_step_id.keys}"
         | 
| 17 18 | 
             
                    end
         | 
| 18 19 |  |