RSpec::Support.require_rspec_core "formatters/console_codes"
RSpec::Support.require_rspec_core "formatters/exception_presenter"
RSpec::Support.require_rspec_core "formatters/helpers"
RSpec::Support.require_rspec_core "shell_escape"

module RSpec::Core
  # Notifications are value objects passed to formatters to provide them
  # with information about a particular event of interest.
  module Notifications
    # @private
    module NullColorizer
      module_function

      def wrap(line, _code_or_symbol)
        line
      end
    end

    # The `StartNotification` represents a notification sent by the reporter
    # when the suite is started. It contains the expected amount of examples
    # to be executed, and the load time of RSpec.
    #
    # @attr count [Fixnum] the number counted
    # @attr load_time [Float] the number of seconds taken to boot RSpec
    #                         and load the spec files
    StartNotification = Struct.new(:count, :load_time)

    # The `ExampleNotification` represents notifications sent by the reporter
    # which contain information about the current (or soon to be) example.
    # It is used by formatters to access information about that example.
    #
    # @example
    #   def example_started(notification)
    #     puts "Hey I started #{notification.example.description}"
    #   end
    #
    # @attr example [RSpec::Core::Example] the current example
    ExampleNotification = Struct.new(:example)
    class ExampleNotification
      # @private
      def self.for(example)
        execution_result = example.execution_result

        return SkippedExampleNotification.new(example) if execution_result.example_skipped?
        return new(example) unless execution_result.status == :pending || execution_result.status == :failed

        klass = if execution_result.pending_fixed?
                  PendingExampleFixedNotification
                elsif execution_result.status == :pending
                  PendingExampleFailedAsExpectedNotification
                else
                  FailedExampleNotification
                end

        klass.new(example)
      end

      private_class_method :new
    end

    # The `ExamplesNotification` represents notifications sent by the reporter
    # which contain information about the suites examples.
    #
    # @example
    #   def stop(notification)
    #     puts "Hey I ran #{notification.examples.size}"
    #   end
    #
    class ExamplesNotification
      def initialize(reporter)
        @reporter = reporter
      end

      # @return [Array<RSpec::Core::Example>] list of examples
      def examples
        @reporter.examples
      end

      # @return [Array<RSpec::Core::Example>] list of failed examples
      def failed_examples
        @reporter.failed_examples
      end

      # @return [Array<RSpec::Core::Example>] list of pending examples
      def pending_examples
        @reporter.pending_examples
      end

      # @return [Array<RSpec::Core::Notifications::ExampleNotification>]
      #         returns examples as notifications
      def notifications
        @notifications ||= format_examples(examples)
      end

      # @return [Array<RSpec::Core::Notifications::FailedExampleNotification>]
      #         returns failed examples as notifications
      def failure_notifications
        @failed_notifications ||= format_examples(failed_examples)
      end

      # @return [Array<RSpec::Core::Notifications::SkippedExampleNotification,
      #                 RSpec::Core::Notifications::PendingExampleFailedAsExpectedNotification>]
      #         returns pending examples as notifications
      def pending_notifications
        @pending_notifications ||= format_examples(pending_examples)
      end

      # @return [String] The list of failed examples, fully formatted in the way
      #   that RSpec's built-in formatters emit.
      def fully_formatted_failed_examples(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        formatted = "\nFailures:\n"

        failure_notifications.each_with_index do |failure, index|
          formatted += failure.fully_formatted(index.next, colorizer)
        end

        formatted
      end

      # @return [String] The list of pending examples, fully formatted in the
      #   way that RSpec's built-in formatters emit.
      def fully_formatted_pending_examples(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        return if RSpec.configuration.pending_failure_output == :skip

        formatted = "\nPending: (Failures listed here are expected and do not affect your suite's status)\n".dup

        pending_notifications.each_with_index do |notification, index|
          formatted << notification.fully_formatted(index.next, colorizer)
        end

        formatted
      end

    private

      def format_examples(examples)
        examples.map do |example|
          ExampleNotification.for(example)
        end
      end
    end

    # The `FailedExampleNotification` extends `ExampleNotification` with
    # things useful for examples that have failure info -- typically a
    # failed or pending spec.
    #
    # @example
    #   def example_failed(notification)
    #     puts "Hey I failed :("
    #     puts "Here's my stack trace"
    #     puts notification.exception.backtrace.join("\n")
    #   end
    #
    # @attr [RSpec::Core::Example] example the current example
    # @see ExampleNotification
    class FailedExampleNotification < ExampleNotification
      public_class_method :new

      # @return [Exception] The example failure
      def exception
        @exception_presenter.exception
      end

      # @return [String] The example description
      def description
        @exception_presenter.description
      end

      # Returns the message generated for this failure line by line.
      #
      # @return [Array<String>] The example failure message
      def message_lines
        @exception_presenter.message_lines
      end

      # Returns the message generated for this failure colorized line by line.
      #
      # @param colorizer [#wrap] An object to colorize the message_lines by
      # @return [Array<String>] The example failure message colorized
      def colorized_message_lines(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        @exception_presenter.colorized_message_lines(colorizer)
      end

      # Returns the failures formatted backtrace.
      #
      # @return [Array<String>] the examples backtrace lines
      def formatted_backtrace
        @exception_presenter.formatted_backtrace
      end

      # Returns the failures colorized formatted backtrace.
      #
      # @param colorizer [#wrap] An object to colorize the message_lines by
      # @return [Array<String>] the examples colorized backtrace lines
      def colorized_formatted_backtrace(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        @exception_presenter.colorized_formatted_backtrace(colorizer)
      end

      # @return [String] The failure information fully formatted in the way that
      #   RSpec's built-in formatters emit.
      def fully_formatted(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        @exception_presenter.fully_formatted(failure_number, colorizer)
      end

      # @return [Array<string>] The failure information fully formatted in the way that
      #   RSpec's built-in formatters emit, split by line.
      def fully_formatted_lines(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        @exception_presenter.fully_formatted_lines(failure_number, colorizer)
      end

    private

      def initialize(example, exception_presenter=Formatters::ExceptionPresenter::Factory.new(example).build)
        @exception_presenter = exception_presenter
        super(example)
      end
    end

    # @deprecated Use {FailedExampleNotification} instead.
    class PendingExampleFixedNotification < FailedExampleNotification; end

    # @deprecated Use {FailedExampleNotification} instead.
    class PendingExampleFailedAsExpectedNotification < FailedExampleNotification; end

    # The `SkippedExampleNotification` extends `ExampleNotification` with
    # things useful for specs that are skipped.
    #
    # @attr [RSpec::Core::Example] example the current example
    # @see ExampleNotification
    class SkippedExampleNotification < ExampleNotification
      public_class_method :new

      # @return [String] The pending detail fully formatted in the way that
      #   RSpec's built-in formatters emit.
      def fully_formatted(pending_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        formatted_caller = RSpec.configuration.backtrace_formatter.backtrace_line(example.location)

        [
          colorizer.wrap("\n  #{pending_number}) #{example.full_description}", :pending),
          "\n     ",
          Formatters::ExceptionPresenter::PENDING_DETAIL_FORMATTER.call(example, colorizer),
          "\n",
          colorizer.wrap("     # #{formatted_caller}\n", :detail)
        ].join("")
      end
    end

    # The `GroupNotification` represents notifications sent by the reporter
    # which contain information about the currently running (or soon to be)
    # example group. It is used by formatters to access information about that
    # group.
    #
    # @example
    #   def example_group_started(notification)
    #     puts "Hey I started #{notification.group.description}"
    #   end
    # @attr group [RSpec::Core::ExampleGroup] the current group
    GroupNotification = Struct.new(:group)

    # The `MessageNotification` encapsulates generic messages that the reporter
    # sends to formatters.
    #
    # @attr message [String] the message
    MessageNotification = Struct.new(:message)

    # The `SeedNotification` holds the seed used to randomize examples and
    # whether that seed has been used or not.
    #
    # @attr seed [Fixnum] the seed used to randomize ordering
    # @attr used [Boolean] whether the seed has been used or not
    SeedNotification = Struct.new(:seed, :used)
    class SeedNotification
      # @api
      # @return [Boolean] has the seed been used?
      def seed_used?
        !!used
      end
      private :used

      # @return [String] The seed information fully formatted in the way that
      #   RSpec's built-in formatters emit.
      def fully_formatted
        "\nRandomized with seed #{seed}\n"
      end
    end

    # The `SummaryNotification` holds information about the results of running
    # a test suite. It is used by formatters to provide information at the end
    # of the test run.
    #
    # @attr duration [Float] the time taken (in seconds) to run the suite
    # @attr examples [Array<RSpec::Core::Example>] the examples run
    # @attr failed_examples [Array<RSpec::Core::Example>] the failed examples
    # @attr pending_examples [Array<RSpec::Core::Example>] the pending examples
    # @attr load_time [Float] the number of seconds taken to boot RSpec
    #                         and load the spec files
    # @attr errors_outside_of_examples_count [Integer] the number of errors that
    #                                                  have occurred processing
    #                                                  the spec suite
    SummaryNotification = Struct.new(:duration, :examples, :failed_examples,
                                     :pending_examples, :load_time,
                                     :errors_outside_of_examples_count)
    class SummaryNotification
      # @api
      # @return [Fixnum] the number of examples run
      def example_count
        @example_count ||= examples.size
      end

      # @api
      # @return [Fixnum] the number of failed examples
      def failure_count
        @failure_count ||= failed_examples.size
      end

      # @api
      # @return [Fixnum] the number of pending examples
      def pending_count
        @pending_count ||= pending_examples.size
      end

      # @api
      # @return [String] A line summarising the result totals of the spec run.
      def totals_line
        summary = Formatters::Helpers.pluralize(example_count, "example") +
          ", " + Formatters::Helpers.pluralize(failure_count, "failure")
        summary += ", #{pending_count} pending" if pending_count > 0
        if errors_outside_of_examples_count > 0
          summary += (
            ", " +
            Formatters::Helpers.pluralize(errors_outside_of_examples_count, "error") +
            " occurred outside of examples"
          )
        end
        summary
      end

      # @api public
      #
      # Wraps the results line with colors based on the configured
      # colors for failure, pending, and success. Defaults to red,
      # yellow, green accordingly.
      #
      # @param colorizer [#wrap] An object which supports wrapping text with
      #                          specific colors.
      # @return [String] A colorized results line.
      def colorized_totals_line(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        if failure_count > 0 || errors_outside_of_examples_count > 0
          colorizer.wrap(totals_line, RSpec.configuration.failure_color)
        elsif pending_count > 0
          colorizer.wrap(totals_line, RSpec.configuration.pending_color)
        else
          colorizer.wrap(totals_line, RSpec.configuration.success_color)
        end
      end

      # @api public
      #
      # Formats failures into a rerunable command format.
      #
      # @param colorizer [#wrap] An object which supports wrapping text with
      #                          specific colors.
      # @return [String] A colorized summary line.
      def colorized_rerun_commands(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        "\nFailed examples:\n\n" +
        failed_examples.map do |example|
          colorizer.wrap("rspec #{rerun_argument_for(example)}", RSpec.configuration.failure_color) + " " +
          colorizer.wrap("# #{example.full_description}",   RSpec.configuration.detail_color)
        end.join("\n")
      end

      # @return [String] a formatted version of the time it took to run the
      #   suite
      def formatted_duration
        Formatters::Helpers.format_duration(duration)
      end

      # @return [String] a formatted version of the time it took to boot RSpec
      #   and load the spec files
      def formatted_load_time
        Formatters::Helpers.format_duration(load_time)
      end

      # @return [String] The summary information fully formatted in the way that
      #   RSpec's built-in formatters emit.
      def fully_formatted(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        formatted = "\nFinished in #{formatted_duration} " \
                    "(files took #{formatted_load_time} to load)\n" \
                    "#{colorized_totals_line(colorizer)}\n"

        unless failed_examples.empty?
          formatted += (colorized_rerun_commands(colorizer) + "\n")
        end

        formatted
      end

    private

      include RSpec::Core::ShellEscape

      def rerun_argument_for(example)
        location = example.location_rerun_argument

        return location unless duplicate_rerun_locations.include?(location)
        return location if RSpec.configuration.force_line_number_for_spec_rerun
        conditionally_quote(example.id)
      end

      def duplicate_rerun_locations
        @duplicate_rerun_locations ||= begin
          locations = RSpec.world.all_examples.map(&:location_rerun_argument)

          Set.new.tap do |s|
            locations.group_by { |l| l }.each do |l, ls|
              s << l if ls.count > 1
            end
          end
        end
      end
    end

    # The `ProfileNotification` holds information about the results of running a
    # test suite when profiling is enabled. It is used by formatters to provide
    # information at the end of the test run for profiling information.
    #
    # @attr duration [Float] the time taken (in seconds) to run the suite
    # @attr examples [Array<RSpec::Core::Example>] the examples run
    # @attr number_of_examples [Fixnum] the number of examples to profile
    # @attr example_groups [Array<RSpec::Core::Profiler>] example groups run
    class ProfileNotification
      def initialize(duration, examples, number_of_examples, example_groups)
        @duration = duration
        @examples = examples
        @number_of_examples = number_of_examples
        @example_groups = example_groups
      end
      attr_reader :duration, :examples, :number_of_examples

      # @return [Array<RSpec::Core::Example>] the slowest examples
      def slowest_examples
        @slowest_examples ||=
          examples.sort_by do |example|
            -example.execution_result.run_time
          end.first(number_of_examples)
      end

      # @return [Float] the time taken (in seconds) to run the slowest examples
      def slow_duration
        @slow_duration ||=
          slowest_examples.inject(0.0) do |i, e|
            i + e.execution_result.run_time
          end
      end

      # @return [String] the percentage of total time taken
      def percentage
        @percentage ||=
          begin
            time_taken = slow_duration / duration
            '%.1f' % ((time_taken.nan? ? 0.0 : time_taken) * 100)
          end
      end

      # @return [Array<RSpec::Core::Example>] the slowest example groups
      def slowest_groups
        @slowest_groups ||= calculate_slowest_groups
      end

    private

      def calculate_slowest_groups
        # stop if we've only one example group
        return {} if @example_groups.keys.length <= 1

        @example_groups.each_value do |hash|
          hash[:average] = hash[:total_time].to_f / hash[:count]
        end

        groups = @example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
        groups.map { |group, data| [group.location, data] }
      end
    end

    # The `DeprecationNotification` is issued by the reporter when a deprecated
    # part of RSpec is encountered. It represents information about the
    # deprecated call site.
    #
    # @attr message [String] A custom message about the deprecation
    # @attr deprecated [String] A custom message about the deprecation (alias of
    #   message)
    # @attr replacement [String] An optional replacement for the deprecation
    # @attr call_site [String] An optional call site from which the deprecation
    #   was issued
    DeprecationNotification = Struct.new(:deprecated, :message, :replacement, :call_site)
    class DeprecationNotification
      private_class_method :new

      # @api
      # Convenience way to initialize the notification
      def self.from_hash(data)
        new data[:deprecated], data[:message], data[:replacement], data[:call_site]
      end
    end

    # `NullNotification` represents a placeholder value for notifications that
    # currently require no information, but we may wish to extend in future.
    class NullNotification
    end

    # `CustomNotification` is used when sending custom events to formatters /
    # other registered listeners, it creates attributes based on supplied hash
    # of options.
    class CustomNotification < Struct
      # @param options [Hash] A hash of method / value pairs to create on this notification
      # @return [CustomNotification]
      #
      # Build a custom notification based on the supplied option key / values.
      def self.for(options={})
        return NullNotification if options.keys.empty?
        new(*options.keys).new(*options.values)
      end
    end
  end
end


def fully_formatted(pending_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
        formatted_caller = RSpec.configuration.backtrace_formatter.backtrace_line(example.location)

        [
          colorizer.wrap("\n  #{pending_number}) #{example.full_description}", :pending),
          "\n     ",
          Formatters::ExceptionPresenter::PENDING_DETAIL_FORMATTER.call(example, colorizer),
          "\n",
          colorizer.wrap("     # #{formatted_caller}\n", :detail)
        ].join("")
      end

class SkippedExampleNotification < < ExampleNotification


def totals_line
        summary = Formatters::Helpers.pluralize(example_count, "example") +
          ", " + Formatters::Helpers.pluralize(failure_count, "failure")
        summary += ", #{pending_count} pending" if pending_count > 0
        if errors_outside_of_examples_count > 0
          summary += (
            ", " +
            Formatters::Helpers.pluralize(errors_outside_of_examples_count, "error") +
            " occurred outside of examples"
          )
        end
        summary
      end


def duplicate_rerun_locations
        @duplicate_rerun_locations ||= begin
          locations = RSpec.world.all_examples.map(&:location_rerun_argument)

          Set.new.tap do |s|
            locations.group_by { |l| l }.each do |l, ls|
              s << l if ls.count > 1
            end
          end
        end
      end


# http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
require 'optparse'

module RSpec::Core
  # @private
  class Parser
    def self.parse(args, source=nil)
      new(args).parse(source)
    end

    attr_reader :original_args

    def initialize(original_args)
      @original_args = original_args
    end

    def parse(source=nil)
      return { :files_or_directories_to_run => [] } if original_args.empty?
      args = original_args.dup

      options = args.delete('--tty') ? { :tty => true } : {}
      begin
        parser(options).parse!(args)
      rescue OptionParser::InvalidOption => e
        abort "#{e.message}#{" (defined in #{source})" if source}\n\n" \
              "Please use --help for a listing of valid options"
      end

      options[:files_or_directories_to_run] = args
      options
    end

  private

    # rubocop:disable Metrics/AbcSize
    # rubocop:disable Metrics/MethodLength
    # rubocop:disable Metrics/CyclomaticComplexity
    # rubocop:disable Metrics/PerceivedComplexity
    def parser(options)
      OptionParser.new do |parser|
        parser.summary_width = 34

        parser.banner = "Usage: rspec [options] [files or directories]\n\n"

        parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |dirs|
          options[:libs] ||= []
          options[:libs].concat(dirs.split(File::PATH_SEPARATOR))
        end

        parser.on('-r', '--require PATH', 'Require a file.') do |path|
          options[:requires] ||= []
          options[:requires] << path
        end

        parser.on('-O', '--options PATH', 'Specify the path to a custom options file.') do |path|
          options[:custom_options_file] = path
        end

        parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
                  '  [defined]           examples and groups are run in the order they are defined',
                  '  [rand]              randomize the order of groups and examples',
                  '  [random]            alias for rand',
                  '  [random:SEED]       e.g. --order random:123',
                  '  [recently-modified] run the most recently modified files first') do |o|
          options[:order] = o
        end

        parser.on('--seed SEED', Integer, 'Equivalent of --order rand:SEED.') do |seed|
          options[:order] = "rand:#{seed}"
        end

        parser.on('--bisect[=verbose]', 'Repeatedly runs the suite in order to isolate the failures to the ',
                  '  smallest reproducible case.') do |argument|
          options[:bisect] = argument || true
          options[:runner] = RSpec::Core::Invocations::Bisect.new
        end

        parser.on('--[no-]fail-fast[=COUNT]', 'Abort the run after a certain number of failures (1 by default).') do |argument|
          if argument == true
            value = 1
          elsif argument == false || argument == 0
            value = false
          else
            begin
              value = Integer(argument)
            rescue ArgumentError
              RSpec.warning "Expected an integer value for `--fail-fast`, got: #{argument.inspect}", :call_site => nil
            end
          end
          set_fail_fast(options, value)
        end

        parser.on('--failure-exit-code CODE', Integer,
                  'Override the exit code used when there are failing specs.') do |code|
          options[:failure_exit_code] = code
        end

        parser.on('--error-exit-code CODE', Integer,
                  'Override the exit code used when there are errors loading or running specs outside of examples.') do |code|
          options[:error_exit_code] = code
        end

        parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |use_drb|
          options[:drb] = use_drb
          options[:runner] = RSpec::Core::Invocations::DRbWithFallback.new if use_drb
        end

        parser.on('--drb-port PORT', 'Port to connect to the DRb server.') do |o|
          options[:drb_port] = o.to_i
        end

        parser.separator("\n  **** Output ****\n\n")

        parser.on('-f', '--format FORMATTER', 'Choose a formatter.',
                  '  [p]rogress (default - dots)',
                  '  [d]ocumentation (group and example names)',
                  '  [h]tml',
                  '  [j]son',
                  '  [f]ailures ("file:line:reason", suitable for editors integration)',
                  '  custom formatter class name') do |o|
          options[:formatters] ||= []
          options[:formatters] << [o]
        end

        parser.on('-o', '--out FILE',
                  'Write output to a file instead of $stdout. This option applies',
                  '  to the previously specified --format, or the default format',
                  '  if no format is specified.'
                 ) do |o|
          options[:formatters] ||= [['progress']]
          options[:formatters].last << o
        end

        parser.on('--deprecation-out FILE', 'Write deprecation warnings to a file instead of $stderr.') do |file|
          options[:deprecation_stream] = file
        end

        parser.on('-b', '--backtrace', 'Enable full backtrace.') do |_o|
          options[:full_backtrace] = true
        end

        parser.on('-c', '--color', '--colour', '') do |_o|
          # flag will be excluded from `--help` output because it is deprecated
          options[:color] = true
          options[:color_mode] = :automatic
        end

        parser.on('--force-color', '--force-colour', 'Force the output to be in color, even if the output is not a TTY') do |_o|
          if options[:color_mode] == :off
            abort "Please only use one of `--force-color` and `--no-color`"
          end
          options[:color_mode] = :on
        end

        parser.on('--no-color', '--no-colour', 'Force the output to not be in color, even if the output is a TTY') do |_o|
          if options[:color_mode] == :on
            abort "Please only use one of --force-color and --no-color"
          end
          options[:color_mode] = :off
        end

        parser.on('-p', '--[no-]profile [COUNT]',
                  'Enable profiling of examples and list the slowest examples (default: 10).') do |argument|
          options[:profile_examples] = if argument.nil?
                                         true
                                       elsif argument == false
                                         false
                                       else
                                         begin
                                           Integer(argument)
                                         rescue ArgumentError
                                           RSpec.warning "Non integer specified as profile count, separate " \
                                                       "your path from options with -- e.g. " \
                                                       "`rspec --profile -- #{argument}`",
                                                         :call_site => nil
                                           true
                                         end
                                       end
        end

        parser.on('--dry-run', 'Print the formatter output of your suite without',
                  '  running any examples or hooks') do |_o|
          options[:dry_run] = true
        end

        parser.on('-w', '--warnings', 'Enable ruby warnings') do
          if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
            # :nocov: on older Ruby without Warning
            Warning[:deprecated] = true
            # :nocov:
          end
          $VERBOSE = true
        end

        parser.separator <<-FILTERING

  **** Filtering/tags ****

    In addition to the following options for selecting specific files, groups, or
    examples, you can select individual examples by appending the line number(s) to
    the filename:

      rspec path/to/a_spec.rb:37:87

    You can also pass example ids enclosed in square brackets:

      rspec path/to/a_spec.rb[1:5,1:6] # run the 5th and 6th examples/groups defined in the 1st group

FILTERING

        parser.on('--only-failures', "Filter to just the examples that failed the last time they ran.") do
          configure_only_failures(options)
        end

        parser.on("-n", "--next-failure", "Apply `--only-failures` and abort after one failure.",
                  "  (Equivalent to `--only-failures --fail-fast --order defined`)") do
          configure_only_failures(options)
          set_fail_fast(options, 1)
          options[:order] ||= 'defined'
        end

        parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
          if options[:pattern]
            options[:pattern] += ',' + o
          else
            options[:pattern] = o
          end
        end

        parser.on('--exclude-pattern PATTERN',
                  'Load files except those matching pattern. Opposite effect of --pattern.') do |o|
          options[:exclude_pattern] = o
        end

        parser.on('-e', '--example STRING', "Run examples whose full nested names include STRING (may be",
                  "  used more than once)") do |o|
          (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
        end

        parser.on('-E', '--example-matches REGEX', "Run examples whose full nested names match REGEX (may be",
                  "  used more than once)") do |o|
          (options[:full_description] ||= []) << Regexp.compile(o)
        end

        parser.on('-t', '--tag TAG[:VALUE]',
                  'Run examples with the specified tag, or exclude examples',
                  'by adding ~ before the tag.',
                  '  - e.g. ~slow',
                  '  - TAG is always converted to a symbol') do |tag|
          filter_type = tag =~ /^~/ ? :exclusion_filter : :inclusion_filter

          name, value = tag.gsub(/^(~@|~|@)/, '').split(':', 2)
          name = name.to_sym

          parsed_value = case value
                         when  nil        then true # The default value for tags is true
                         when 'true'      then true
                         when 'false'     then false
                         when 'nil'       then nil
                         when /^:/        then value[1..-1].to_sym
                         when /^\d+$/     then Integer(value)
                         when /^\d+.\d+$/ then Float(value)
                         else
                           value
                         end

          add_tag_filter(options, filter_type, name, parsed_value)
        end

        parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
                  '  be a path to a file or a directory).') do |path|
          options[:default_path] = path
        end

        parser.separator("\n  **** Utility ****\n\n")

        parser.on('--init', 'Initialize your project with RSpec.') do |_cmd|
          options[:runner] = RSpec::Core::Invocations::InitializeProject.new
        end

        parser.on('-v', '--version', 'Display the version.') do
          options[:runner] = RSpec::Core::Invocations::PrintVersion.new
        end

        # These options would otherwise be confusing to users, so we forcibly
        # prevent them from executing.
        #
        #   * --I is too similar to -I.
        #   * -d was a shorthand for --debugger, which is removed, but now would
        #     trigger --default-path.
        invalid_options = %w[-d --I]

        hidden_options = invalid_options + %w[-c]

        parser.on_tail('-h', '--help', "You're looking at it.") do
          options[:runner] = RSpec::Core::Invocations::PrintHelp.new(parser, hidden_options)
        end

        # This prevents usage of the invalid_options.
        invalid_options.each do |option|
          parser.on(option) do
            raise OptionParser::InvalidOption.new
          end
        end
      end
    end
    # rubocop:enable Metrics/AbcSize
    # rubocop:enable Metrics/MethodLength
    # rubocop:enable Metrics/CyclomaticComplexity
    # rubocop:enable Metrics/PerceivedComplexity

    def add_tag_filter(options, filter_type, tag_name, value=true)
      (options[filter_type] ||= {})[tag_name] = value
    end

    def set_fail_fast(options, value)
      options[:fail_fast] = value
    end

    def configure_only_failures(options)
      options[:only_failures] = true
      add_tag_filter(options, :inclusion_filter, :last_run_status, 'failed')
    end
  end
end


module RSpec
  module Core
    # @private
    module Ordering
      # @private
      # The default global ordering (defined order).
      class Identity
        def order(items)
          items
        end
      end

      # @private
      # Orders items randomly.
      class Random
        def initialize(configuration)
          @configuration = configuration
          @used = false
        end

        def used?
          @used
        end

        def order(items)
          @used = true

          seed = @configuration.seed.to_s
          items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
        end

      private

        # http://en.wikipedia.org/wiki/Jenkins_hash_function
        # Jenkins provides a good distribution and is simpler than MD5.
        # It's a bit slower than MD5 (primarily because `Digest::MD5` is
        # implemented in C) but has the advantage of not requiring us
        # to load another part of stdlib, which we try to minimize.
        def jenkins_hash_digest(string)
          hash = 0

          string.each_byte do |byte|
            hash += byte
            hash &= MAX_32_BIT
            hash += ((hash << 10) & MAX_32_BIT)
            hash &= MAX_32_BIT
            hash ^= hash >> 6
          end

          hash += ((hash << 3) & MAX_32_BIT)
          hash &= MAX_32_BIT
          hash ^= hash >> 11
          hash += ((hash << 15) & MAX_32_BIT)
          hash &= MAX_32_BIT
          hash
        end

        MAX_32_BIT = 4_294_967_295
      end

      # @private
      # Orders items by modification time (most recent modified first).
      class RecentlyModified
        def order(list)
          list.sort_by { |item| -File.mtime(item.metadata[:absolute_file_path]).to_i }
        end
      end

      # @private
      # Orders items based on a custom block.
      class Custom
        def initialize(callable)
          @callable = callable
        end

        def order(list)
          @callable.call(list)
        end
      end

      # @private
      # A strategy which delays looking up the ordering until needed
      class Delayed
        def initialize(registry, name)
          @registry = registry
          @name = name
        end

        def order(list)
          strategy.order(list)
        end

        private

        def strategy
          @strategy ||= lookup_strategy
        end

        def lookup_strategy
          raise "Undefined ordering strategy #{@name.inspect}" unless @registry.has_strategy?(@name)
          @registry.fetch(@name)
        end
      end

      # @private
      # Stores the different ordering strategies.
      class Registry
        def initialize(configuration)
          @configuration = configuration
          @strategies    = {}

          register(:random, Random.new(configuration))
          register(:recently_modified, RecentlyModified.new)

          identity = Identity.new
          register(:defined, identity)

          # The default global ordering is --defined.
          register(:global, identity)
        end

        def fetch(name, &fallback)
          @strategies.fetch(name, &fallback)
        end

        def has_strategy?(name)
          @strategies.key?(name)
        end

        def register(sym, strategy)
          @strategies[sym] = strategy
        end

        def used_random_seed?
          @strategies[:random].used?
        end
      end

      # @private
      # Manages ordering configuration.
      #
      # @note This is not intended to be used externally. Use
      #       the APIs provided by `RSpec::Core::Configuration` instead.
      class ConfigurationManager
        attr_reader :seed, :ordering_registry

        def initialize
          @ordering_registry = Registry.new(self)
          @seed = rand(0xFFFF)
          @seed_forced = false
          @order_forced = false
        end

        def seed_used?
          ordering_registry.used_random_seed?
        end

        def seed=(seed)
          return if @seed_forced
          register_ordering(:global, ordering_registry.fetch(:random))
          @seed = seed.to_i
        end

        def order=(type)
          order, seed = type.to_s.split(':')
          @seed = seed.to_i if seed

          ordering_name = if order.include?('rand')
                            :random
                          elsif order == 'defined'
                            :defined
                          elsif order == 'recently-modified'
                            :recently_modified
                          else
                            order.to_sym
                          end

          if ordering_name
            strategy =
              if ordering_registry.has_strategy?(ordering_name)
                ordering_registry.fetch(ordering_name)
              else
                Delayed.new(ordering_registry, ordering_name)
              end

            register_ordering(:global, strategy)
          end
        end

        def force(hash)
          if hash.key?(:seed)
            self.seed = hash[:seed]
            @seed_forced  = true
            @order_forced = true
          elsif hash.key?(:order)
            self.order = hash[:order]
            @order_forced = true
          end
        end

        def register_ordering(name, strategy=Custom.new(Proc.new { |l| yield l }))
          return if @order_forced && name == :global
          ordering_registry.register(name, strategy)
        end
      end
    end
  end
end


def order=(type)
          order, seed = type.to_s.split(':')
          @seed = seed.to_i if seed

          ordering_name = if order.include?('rand')
                            :random
                          elsif order == 'defined'
                            :defined
                          elsif order == 'recently-modified'
                            :recently_modified
                          else
                            order.to_sym
                          end

          if ordering_name
            strategy =
              if ordering_registry.has_strategy?(ordering_name)
                ordering_registry.fetch(ordering_name)
              else
                Delayed.new(ordering_registry, ordering_name)
              end

            register_ordering(:global, strategy)
          end
        end


def force(hash)
          if hash.key?(:seed)
            self.seed = hash[:seed]
            @seed_forced  = true
            @order_forced = true
          elsif hash.key?(:order)
            self.order = hash[:order]
            @order_forced = true
          end
        end


module RSpec
  module Core
    # Provides methods to mark examples as pending. These methods are available
    # to be called from within any example or hook.
    module Pending
      # Raised in the middle of an example to indicate that it should be marked
      # as skipped.
      class SkipDeclaredInExample < StandardError
        attr_reader :argument

        def initialize(argument)
          @argument = argument
        end
      end

      # If Test::Unit is loaded, we'll use its error as baseclass, so that
      # Test::Unit will report unmet RSpec expectations as failures rather than
      # errors.
      begin
        class PendingExampleFixedError < Test::Unit::AssertionFailedError; end
      rescue
        class PendingExampleFixedError < StandardError; end
      end

      # @private
      NO_REASON_GIVEN = 'No reason given'

      # @private
      NOT_YET_IMPLEMENTED = 'Not yet implemented'

      # @overload pending()
      # @overload pending(message)
      #
      # Marks an example as pending. The rest of the example will still be
      # executed, and if it passes the example will fail to indicate that the
      # pending can be removed.
      #
      # @param message [String] optional message to add to the summary report.
      #
      # @example
      #     describe "some behaviour" do
      #       # reported as "Pending: no reason given"
      #       it "is pending with no message" do
      #         pending
      #         raise "broken"
      #       end
      #
      #       # reported as "Pending: something else getting finished"
      #       it "is pending with a custom message" do
      #         pending("something else getting finished")
      #         raise "broken"
      #       end
      #     end
      #
      # @note When using `pending` inside an example body using this method
      #   hooks, such as `before(:example)`, have already be run. This means that
      #   a failure from the code in the `before` hook will prevent the example
      #   from being considered pending, as the example body would not be
      #   executed. If you need to consider hooks as pending as well you can use
      #   the pending metadata as an alternative, e.g.
      #   `it "does something", pending: "message"`.
      def pending(message=nil, &_block)
        current_example = RSpec.current_example

        if block_given?
          raise ArgumentError, <<-EOS.gsub(/^\s+\|/, '')
            |The semantics of `RSpec::Core::Pending#pending` have changed in
            |RSpec 3. In RSpec 2.x, it caused the example to be skipped. In
            |RSpec 3, the rest of the example is still run but is expected to
            |fail, and will be marked as a failure (rather than as pending) if
            |the example passes.
            |
            |Passing a block within an example is now deprecated. Marking the
            |example as pending provides the same behavior in RSpec 3 which was
            |provided only by the block in RSpec 2.x.
            |
            |Move the code in the block provided to `pending` into the rest of
            |the example body.
            |
            |Called from #{CallerFilter.first_non_rspec_line}.
            |
          EOS
        elsif current_example
          Pending.mark_pending! current_example, message
        else
          raise "`pending` may not be used outside of examples, such as in " \
                "before(:context). Maybe you want `skip`?"
        end
      end

      # @overload skip()
      # @overload skip(message)
      #
      # Marks an example as pending and skips execution.
      #
      # @param message [String] optional message to add to the summary report.
      #
      # @example
      #     describe "an example" do
      #       # reported as "Pending: no reason given"
      #       it "is skipped with no message" do
      #         skip
      #       end
      #
      #       # reported as "Pending: something else getting finished"
      #       it "is skipped with a custom message" do
      #         skip "something else getting finished"
      #       end
      #     end
      def skip(message=nil)
        current_example = RSpec.current_example

        Pending.mark_skipped!(current_example, message) if current_example

        raise SkipDeclaredInExample.new(message)
      end

      # @private
      #
      # Mark example as skipped.
      #
      # @param example [RSpec::Core::Example] the example to mark as skipped
      # @param message_or_bool [Boolean, String] the message to use, or true
      def self.mark_skipped!(example, message_or_bool)
        Pending.mark_pending! example, message_or_bool
        example.metadata[:skip] = true
      end

      # @private
      #
      # Mark example as pending.
      #
      # @param example [RSpec::Core::Example] the example to mark as pending
      # @param message_or_bool [Boolean, String] the message to use, or true
      def self.mark_pending!(example, message_or_bool)
        message = if !message_or_bool || !(String === message_or_bool)
                    NO_REASON_GIVEN
                  else
                    message_or_bool
                  end

        example.metadata[:pending] = true
        example.execution_result.pending_message = message
        example.execution_result.pending_fixed = false
      end

      # @private
      #
      # Mark example as fixed.
      #
      # @param example [RSpec::Core::Example] the example to mark as fixed
      def self.mark_fixed!(example)
        example.execution_result.pending_fixed = true
      end
    end
  end
end


def self.mark_pending!(example, message_or_bool)
        message = if !message_or_bool || !(String === message_or_bool)
                    NO_REASON_GIVEN
                  else
                    message_or_bool
                  end

        example.metadata[:pending] = true
        example.execution_result.pending_message = message
        example.execution_result.pending_fixed = false
      end


require 'rake'
require 'rake/tasklib'
require 'rspec/support'

RSpec::Support.require_rspec_support "ruby_features"

# :nocov:
unless RSpec::Support.respond_to?(:require_rspec_core)
  RSpec::Support.define_optimized_require_for_rspec(:core) { |f| require_relative "../#{f}" }
end
# :nocov:

RSpec::Support.require_rspec_core "shell_escape"

module RSpec
  module Core
    # RSpec rake task
    #
    # @see Rakefile
    class RakeTask < ::Rake::TaskLib
      include ::Rake::DSL if defined?(::Rake::DSL)
      include RSpec::Core::ShellEscape

      # Default path to the RSpec executable.
      DEFAULT_RSPEC_PATH = File.expand_path('../../../../exe/rspec', __FILE__)

      # Default pattern for spec files.
      DEFAULT_PATTERN = 'spec/**{,/*/**}/*_spec.rb'

      # Name of task. Defaults to `:spec`.
      attr_accessor :name

      # Files matching this pattern will be loaded.
      # Defaults to `'spec/**{,/*/**}/*_spec.rb'`.
      attr_accessor :pattern

      # Files matching this pattern will be excluded.
      # Defaults to `nil`.
      attr_accessor :exclude_pattern

      # Whether or not to fail Rake when an error occurs (typically when
      # examples fail). Defaults to `true`.
      attr_accessor :fail_on_error

      # A message to print to stderr when there are failures.
      attr_accessor :failure_message

      if RUBY_VERSION < "1.9.0" || Support::Ruby.jruby?
        # Run RSpec with a clean (empty) environment is not supported
        # :nocov:
        def with_clean_environment=(_value)
          raise ArgumentError, "Running in a clean environment is not supported on Ruby versions before 1.9.0"
        end

        # Run RSpec with a clean (empty) environment is not supported
        def with_clean_environment
          false
        end
        # :nocov:
      else
        # Run RSpec with a clean (empty) environment.
        attr_accessor :with_clean_environment
      end

      # Use verbose output. If this is set to true, the task will print the
      # executed spec command to stdout. Defaults to `true`.
      attr_accessor :verbose

      # Command line options to pass to ruby. Defaults to `nil`.
      attr_accessor :ruby_opts

      # Path to RSpec. Defaults to the absolute path to the
      # rspec binary from the loaded rspec-core gem.
      attr_accessor :rspec_path

      # Command line options to pass to RSpec. Defaults to `nil`.
      attr_accessor :rspec_opts

      def initialize(*args, &task_block)
        @name          = args.shift || :spec
        @ruby_opts     = nil
        @rspec_opts    = nil
        @verbose       = true
        @fail_on_error = true
        @rspec_path    = DEFAULT_RSPEC_PATH
        @pattern       = DEFAULT_PATTERN

        define(args, &task_block)
      end

      # @private
      def run_task(verbose)
        command = spec_command
        puts command if verbose

        if with_clean_environment
          return if system({}, command, :unsetenv_others => true)
        else
          return if system(command)
        end

        puts failure_message if failure_message

        return unless fail_on_error
        $stderr.puts "#{command} failed" if verbose
        exit $?.exitstatus || 1
      end

    private

      # @private
      def define(args, &task_block)
        desc "Run RSpec code examples" unless ::Rake.application.last_description

        task name, *args do |_, task_args|
          RakeFileUtils.__send__(:verbose, verbose) do
            task_block.call(*[self, task_args].slice(0, task_block.arity)) if task_block
            run_task verbose
          end
        end
      end

      def file_inclusion_specification
        if ENV['SPEC']
          FileList[ENV['SPEC']].sort
        elsif String === pattern && !File.exist?(pattern)
          return if [*rspec_opts].any? { |opt| opt =~ /--pattern/ }
          "--pattern #{escape pattern}"
        else
          # Before RSpec 3.1, we used `FileList` to get the list of matched
          # files, and then pass that along to the `rspec` command. Starting
          # with 3.1, we prefer to pass along the pattern as-is to the `rspec`
          # command, for 3 reasons:
          #
          #   * It's *much* less verbose to pass one `--pattern` option than a
          #     long list of files.
          #   * It ensures `task.pattern` and `--pattern` have the same
          #     behavior.
          #   * It fixes a bug, where
          #     `task.pattern = pattern_that_matches_no_files` would run *all*
          #     files because it would cause no pattern or file args to get
          #     passed to `rspec`, which causes all files to get run.
          #
          # However, `FileList` is *far* more flexible than the `--pattern`
          # option. Specifically, it supports individual files and directories,
          # as well as arrays of files, directories and globs, as well as other
          # `FileList` objects.
          #
          # For backwards compatibility, we have to fall back to using FileList
          # if the user has passed a `pattern` option that will not work with
          # `--pattern`.
          #
          # TODO: consider deprecating support for this and removing it in
          #   RSpec 4.
          FileList[pattern].sort.map { |file| escape file }
        end
      end

      def file_exclusion_specification
        " --exclude-pattern #{escape exclude_pattern}" if exclude_pattern
      end

      def spec_command
        cmd_parts = []
        cmd_parts << RUBY
        cmd_parts << ruby_opts
        cmd_parts << rspec_load_path
        cmd_parts << escape(rspec_path)
        cmd_parts << file_inclusion_specification
        cmd_parts << file_exclusion_specification
        cmd_parts << rspec_opts
        cmd_parts.flatten.reject(&blank).join(" ")
      end

      def blank
        lambda { |s| s.nil? || s == "" }
      end

      def rspec_load_path
        @rspec_load_path ||= begin
          core_and_support = $LOAD_PATH.grep(
            /#{File::SEPARATOR}rspec-(core|support)[^#{File::SEPARATOR}]*#{File::SEPARATOR}lib/
          ).uniq

          "-I#{core_and_support.map { |file| escape file }.join(File::PATH_SEPARATOR)}"
        end
      end
    end
  end
end


def run_task(verbose)
        command = spec_command
        puts command if verbose

        if with_clean_environment
          return if system({}, command, :unsetenv_others => true)
        else
          return if system(command)
        end

        puts failure_message if failure_message

        return unless fail_on_error
        $stderr.puts "#{command} failed" if verbose
        exit $?.exitstatus || 1
      end


module RSpec::Core
  # A reporter will send notifications to listeners, usually formatters for the
  # spec suite run.
  class Reporter
    # @private
    RSPEC_NOTIFICATIONS = Set.new(
      [
        :close, :deprecation, :deprecation_summary, :dump_failures, :dump_pending,
        :dump_profile, :dump_summary, :example_failed, :example_group_finished,
        :example_group_started, :example_passed, :example_pending, :example_started,
        :message, :seed, :start, :start_dump, :stop, :example_finished
      ])

    def initialize(configuration)
      @configuration = configuration
      @listeners = Hash.new { |h, k| h[k] = Set.new }
      @examples = []
      @failed_examples = []
      @pending_examples = []
      @duration = @start = @load_time = nil
      @non_example_exception_count = 0
      @setup_default = lambda {}
      @setup = false
      @profiler = nil
    end

    # @private
    attr_reader :examples, :failed_examples, :pending_examples

    # Registers a listener to a list of notifications. The reporter will send
    # notification of events to all registered listeners.
    #
    # @param listener [Object] An object that wishes to be notified of reporter
    #   events
    # @param notifications [Array] Array of symbols represents the events a
    #   listener wishes to subscribe too
    def register_listener(listener, *notifications)
      notifications.each do |notification|
        @listeners[notification.to_sym] << listener
      end
      true
    end

    # @private
    def prepare_default(loader, output_stream, deprecation_stream)
      @setup_default = lambda do
        loader.setup_default output_stream, deprecation_stream
      end
    end

    # @private
    def registered_listeners(notification)
      @listeners[notification].to_a
    end

    # @overload report(count, &block)
    # @overload report(count, &block)
    # @param expected_example_count [Integer] the number of examples being run
    # @yield [Block] block yields itself for further reporting.
    #
    # Initializes the report run and yields itself for further reporting. The
    # block is required, so that the reporter can manage cleaning up after the
    # run.
    #
    # @example
    #
    #     reporter.report(group.examples.size) do |r|
    #       example_groups.map {|g| g.run(r) }
    #     end
    #
    def report(expected_example_count)
      start(expected_example_count)
      begin
        yield self
      ensure
        finish
      end
    end

    # @param exit_code [Integer] the exit_code to be return by the reporter
    #
    # Reports a run that exited early without having run any examples.
    #
    def exit_early(exit_code)
      report(0) { exit_code }
    end

    # @private
    def start(expected_example_count, time=RSpec::Core::Time.now)
      @start = time
      @load_time = (@start - @configuration.start_time).to_f
      notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
      notify :start, Notifications::StartNotification.new(expected_example_count, @load_time)
    end

    # @param message [#to_s] A message object to send to formatters
    #
    # Send a custom message to supporting formatters.
    def message(message)
      notify :message, Notifications::MessageNotification.new(message)
    end

    # @param event [Symbol] Name of the custom event to trigger on formatters
    # @param options [Hash] Hash of arguments to provide via `CustomNotification`
    #
    # Publish a custom event to supporting registered formatters.
    # @see RSpec::Core::Notifications::CustomNotification
    def publish(event, options={})
      if RSPEC_NOTIFICATIONS.include? event
        raise "RSpec::Core::Reporter#publish is intended for sending custom " \
              "events not internal RSpec ones, please rename your custom event."
      end
      notify event, Notifications::CustomNotification.for(options)
    end

    # @private
    def example_group_started(group)
      notify :example_group_started, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
    end

    # @private
    def example_group_finished(group)
      notify :example_group_finished, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
    end

    # @private
    def example_started(example)
      @examples << example
      notify :example_started, Notifications::ExampleNotification.for(example)
    end

    # @private
    def example_finished(example)
      notify :example_finished, Notifications::ExampleNotification.for(example)
    end

    # @private
    def example_passed(example)
      notify :example_passed, Notifications::ExampleNotification.for(example)
    end

    # @private
    def example_failed(example)
      @failed_examples << example
      notify :example_failed, Notifications::ExampleNotification.for(example)
    end

    # @private
    def example_pending(example)
      @pending_examples << example
      notify :example_pending, Notifications::ExampleNotification.for(example)
    end

    # @private
    def deprecation(hash)
      notify :deprecation, Notifications::DeprecationNotification.from_hash(hash)
    end

    # @private
    # Provides a way to notify of an exception that is not tied to any
    # particular example (such as an exception encountered in a :suite hook).
    # Exceptions will be formatted the same way they normally are.
    def notify_non_example_exception(exception, context_description)
      @configuration.world.non_example_failure = true
      @non_example_exception_count += 1

      example = Example.new(AnonymousExampleGroup, context_description, {})
      presenter = Formatters::ExceptionPresenter.new(exception, example, :indentation => 0)
      message presenter.fully_formatted(nil)
    end

    # @private
    def finish
      close_after do
        stop
        notify :start_dump,    Notifications::NullNotification
        notify :dump_pending,  Notifications::ExamplesNotification.new(self)
        notify :dump_failures, Notifications::ExamplesNotification.new(self)
        notify :deprecation_summary, Notifications::NullNotification
        unless mute_profile_output?
          notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
                                                                       @configuration.profile_examples,
                                                                       @profiler.example_groups)
        end
        notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
                                                                     @pending_examples, @load_time,
                                                                     @non_example_exception_count)
        notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
      end
    end

    # @private
    def close_after
      yield
    ensure
      close
    end

    # @private
    def stop
      @duration = (RSpec::Core::Time.now - @start).to_f if @start
      notify :stop, Notifications::ExamplesNotification.new(self)
    end

    # @private
    def notify(event, notification)
      ensure_listeners_ready
      registered_listeners(event).each do |formatter|
        formatter.__send__(event, notification)
      end
    end

    # @private
    def abort_with(msg, exit_status)
      message(msg)
      close
      exit!(exit_status)
    end

    # @private
    def fail_fast_limit_met?
      return false unless (fail_fast = @configuration.fail_fast)

      if fail_fast == true
        @failed_examples.any?
      else
        fail_fast <= @failed_examples.size
      end
    end

  private

    def ensure_listeners_ready
      return if @setup

      @setup_default.call
      @profiler = Profiler.new
      register_listener @profiler, *Profiler::NOTIFICATIONS
      @setup = true
    end

    def close
      notify :close, Notifications::NullNotification
    end

    def mute_profile_output?
      # Don't print out profiled info if there are failures and `--fail-fast` is
      # used, it just clutters the output.
      !@configuration.profile_examples? || fail_fast_limit_met?
    end

    def seed_used?
      @configuration.seed && @configuration.seed_used?
    end
  end

  # @private
  # # Used in place of a {Reporter} for situations where we don't want reporting output.
  class NullReporter
    def self.method_missing(*)
      # ignore
    end
    private_class_method :method_missing
  end
end


def finish
      close_after do
        stop
        notify :start_dump,    Notifications::NullNotification
        notify :dump_pending,  Notifications::ExamplesNotification.new(self)
        notify :dump_failures, Notifications::ExamplesNotification.new(self)
        notify :deprecation_summary, Notifications::NullNotification
        unless mute_profile_output?
          notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
                                                                       @configuration.profile_examples,
                                                                       @profiler.example_groups)
        end
        notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
                                                                     @pending_examples, @load_time,
                                                                     @non_example_exception_count)
        notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
      end
    end


# This is borrowed (slightly modified) from Scott Taylor's
# project_path project:
#   http://github.com/smtlaissezfaire/project_path
module RSpec
  module Core
    # @private
    module RubyProject
      def add_to_load_path(*dirs)
        dirs.each { |dir| add_dir_to_load_path(File.join(root, dir)) }
      end

      def add_dir_to_load_path(dir)
        $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
      end

      def root
        @project_root ||= determine_root
      end

      def determine_root
        find_first_parent_containing('spec') || '.'
      end

      def find_first_parent_containing(dir)
        ascend_until { |path| File.exist?(File.join(path, dir)) }
      end

      def ascend_until
        fs = File::SEPARATOR
        escaped_slash = "\\#{fs}"
        special = "_RSPEC_ESCAPED_SLASH_"
        project_path = File.expand_path(".")
        parts = project_path.gsub(escaped_slash, special).squeeze(fs).split(fs).map do |x|
          x.gsub(special, escaped_slash)
        end

        until parts.empty?
          path = parts.join(fs)
          path = fs if path == ""
          return path if yield(path)
          parts.pop
        end
      end

      module_function :add_to_load_path
      module_function :add_dir_to_load_path
      module_function :root
      module_function :determine_root
      module_function :find_first_parent_containing
      module_function :ascend_until
    end
  end
end


module RSpec
  module Core
    # Provides the main entry point to run a suite of RSpec examples.
    class Runner
      # @attr_reader
      # @private
      attr_reader :options, :configuration, :world

      # Register an `at_exit` hook that runs the suite when the process exits.
      #
      # @note This is not generally needed. The `rspec` command takes care
      #       of running examples for you without involving an `at_exit`
      #       hook. This is only needed if you are running specs using
      #       the `ruby` command, and even then, the normal way to invoke
      #       this is by requiring `rspec/autorun`.
      def self.autorun
        if autorun_disabled?
          RSpec.deprecate("Requiring `rspec/autorun` when running RSpec via the `rspec` command")
          return
        elsif installed_at_exit? || running_in_drb?
          return
        end

        at_exit { perform_at_exit }
        @installed_at_exit = true
      end

      # @private
      def self.perform_at_exit
        # Don't bother running any specs and just let the program terminate
        # if we got here due to an unrescued exception (anything other than
        # SystemExit, which is raised when somebody calls Kernel#exit).
        return unless $!.nil? || $!.is_a?(SystemExit)

        # We got here because either the end of the program was reached or
        # somebody called Kernel#exit. Run the specs and then override any
        # existing exit status with RSpec's exit status if any specs failed.
        invoke
      end

      # Runs the suite of specs and exits the process with an appropriate exit
      # code.
      def self.invoke
        disable_autorun!
        status = run(ARGV, $stderr, $stdout).to_i
        exit(status) if status != 0
      end

      # Run a suite of RSpec examples. Does not exit.
      #
      # This is used internally by RSpec to run a suite, but is available
      # for use by any other automation tool.
      #
      # If you want to run this multiple times in the same process, and you
      # want files like `spec_helper.rb` to be reloaded, be sure to load `load`
      # instead of `require`.
      #
      # @param args [Array] command-line-supported arguments
      # @param err [IO] error stream
      # @param out [IO] output stream
      # @return [Fixnum] exit status code. 0 if all specs passed,
      #   or the configured failure exit code (1 by default) if specs
      #   failed.
      def self.run(args, err=$stderr, out=$stdout)
        trap_interrupt
        options = ConfigurationOptions.new(args)

        if options.options[:runner]
          options.options[:runner].call(options, err, out)
        else
          new(options).run(err, out)
        end
      end

      def initialize(options, configuration=RSpec.configuration, world=RSpec.world)
        @options       = options
        @configuration = configuration
        @world         = world
      end

      # Configures and runs a spec suite.
      #
      # @param err [IO] error stream
      # @param out [IO] output stream
      def run(err, out)
        setup(err, out)
        return @configuration.reporter.exit_early(exit_code) if RSpec.world.wants_to_quit

        run_specs(@world.ordered_example_groups).tap do
          persist_example_statuses
        end
      end

      # Wires together the various configuration objects and state holders.
      #
      # @param err [IO] error stream
      # @param out [IO] output stream
      def setup(err, out)
        configure(err, out)
        return if RSpec.world.wants_to_quit

        @configuration.load_spec_files
      ensure
        @world.announce_filters
      end

      # Runs the provided example groups.
      #
      # @param example_groups [Array<RSpec::Core::ExampleGroup>] groups to run
      # @return [Fixnum] exit status code. 0 if all specs passed,
      #   or the configured failure exit code (1 by default) if specs
      #   failed.
      def run_specs(example_groups)
        examples_count = @world.example_count(example_groups)
        examples_passed = @configuration.reporter.report(examples_count) do |reporter|
          @configuration.with_suite_hooks do
            if examples_count == 0 && @configuration.fail_if_no_examples
              return @configuration.failure_exit_code
            end

            example_groups.map { |g| g.run(reporter) }.all?
          end
        end

        exit_code(examples_passed)
      end

      # @private
      def configure(err, out)
        @configuration.error_stream = err
        @configuration.output_stream = out if @configuration.output_stream == $stdout
        @options.configure(@configuration)
      end

      # @private
      def self.disable_autorun!
        @autorun_disabled = true
      end

      # @private
      def self.autorun_disabled?
        @autorun_disabled ||= false
      end

      # @private
      def self.installed_at_exit?
        @installed_at_exit ||= false
      end

      # @private
      def self.running_in_drb?
        return false unless defined?(DRb)

        server = begin
                   DRb.current_server
                 rescue DRb::DRbServerNotFound
                   return false
                 end

        return false unless server && server.alive?

        require 'socket'
        require 'uri'

        local_ipv4 = begin
                       IPSocket.getaddress(Socket.gethostname)
                     rescue SocketError
                       return false
                     end

        ["127.0.0.1", "localhost", local_ipv4].any? { |addr| addr == URI(DRb.current_server.uri).host }
      end

      # @private
      def self.trap_interrupt
        trap('INT') { handle_interrupt }
      end

      # @private
      def self.handle_interrupt
        if RSpec.world.wants_to_quit
          exit!(1)
        else
          RSpec.world.wants_to_quit = true

          $stderr.puts(
            "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit " \
            "(warning: at_exit hooks will be skipped if you force quit)."
          )
        end
      end

      # @private
      def exit_code(examples_passed=false)
        return @configuration.error_exit_code || @configuration.failure_exit_code if @world.non_example_failure
        return @configuration.failure_exit_code unless examples_passed

        0
      end

    private

      def persist_example_statuses
        return if @configuration.dry_run
        return unless (path = @configuration.example_status_persistence_file_path)

        ExampleStatusPersister.persist(@world.all_examples, path)
      rescue SystemCallError => e
        RSpec.warning "Could not write example statuses to #{path} (configured as " \
                      "`config.example_status_persistence_file_path`) due to a " \
                      "system error: #{e.inspect}. Please check that the config " \
                      "option is set to an accessible, valid file path", :call_site => nil
      end
    end
  end
end


def self.running_in_drb?
        return false unless defined?(DRb)

        server = begin
                   DRb.current_server
                 rescue DRb::DRbServerNotFound
                   return false
                 end

        return false unless server && server.alive?

        require 'socket'
        require 'uri'

        local_ipv4 = begin
                       IPSocket.getaddress(Socket.gethostname)
                     rescue SocketError
                       return false
                     end

        ["127.0.0.1", "localhost", local_ipv4].any? { |addr| addr == URI(DRb.current_server.uri).host }
      end


def self.handle_interrupt
        if RSpec.world.wants_to_quit
          exit!(1)
        else
          RSpec.world.wants_to_quit = true

          $stderr.puts(
            "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit " \
            "(warning: at_exit hooks will be skipped if you force quit)."
          )
        end
      end


module RSpec
  module Core
    # A sandbox isolates the enclosed code into an environment that looks 'new'
    # meaning globally accessed objects are reset for the duration of the
    # sandbox.
    #
    # @note This module is not normally available. You must require
    #   `rspec/core/sandbox` to load it.
    module Sandbox
      # Execute a provided block with RSpec global objects (configuration,
      # world) reset.  This is used to test RSpec with RSpec.
      #
      # When calling this the configuration is passed into the provided block.
      # Use this to set custom configs for your sandboxed examples.
      #
      # ```
      # Sandbox.sandboxed do |config|
      #   config.before(:context) { RSpec.current_example = nil }
      # end
      # ```
      def self.sandboxed
        orig_config  = RSpec.configuration
        orig_world   = RSpec.world
        orig_example = RSpec.current_example

        RSpec.configuration = RSpec::Core::Configuration.new
        RSpec.world         = RSpec::Core::World.new(RSpec.configuration)

        yield RSpec.configuration
      ensure
        RSpec.configuration   = orig_config
        RSpec.world           = orig_world
        RSpec.current_example = orig_example
      end
    end
  end
end


RSpec::Support.require_rspec_support "with_keywords_when_needed"

module RSpec
  module Core
    # Represents some functionality that is shared with multiple example groups.
    # The functionality is defined by the provided block, which is lazily
    # eval'd when the `SharedExampleGroupModule` instance is included in an example
    # group.
    class SharedExampleGroupModule < Module
      # @private
      attr_reader :definition

      def initialize(description, definition, metadata)
        @description = description
        @definition  = definition
        @metadata    = metadata
      end

      # Provides a human-readable representation of this module.
      def inspect
        "#<#{self.class.name} #{@description.inspect}>"
      end
      alias to_s inspect

      # Ruby callback for when a module is included in another module is class.
      # Our definition evaluates the shared group block in the context of the
      # including example group.
      def included(klass)
        inclusion_line = klass.metadata[:location]
        include_in klass, inclusion_line, [], nil
      end

      # @private
      def include_in(klass, inclusion_line, args, customization_block)
        klass.update_inherited_metadata(@metadata) unless @metadata.empty?

        SharedExampleGroupInclusionStackFrame.with_frame(@description, inclusion_line) do
          RSpec::Support::WithKeywordsWhenNeeded.class_exec(klass, *args, &@definition)
          klass.class_exec(&customization_block) if customization_block
        end
      end
    end

    # Shared example groups let you define common context and/or common
    # examples that you wish to use in multiple example groups.
    #
    # When defined, the shared group block is stored for later evaluation.
    # It can later be included in an example group either explicitly
    # (using `include_examples`, `include_context` or `it_behaves_like`)
    # or implicitly (via matching metadata).
    #
    # Named shared example groups are scoped based on where they are
    # defined. Shared groups defined in an example group are available
    # for inclusion in that example group or any child example groups,
    # but not in any parent or sibling example groups. Shared example
    # groups defined at the top level can be included from any example group.
    module SharedExampleGroup
      # @overload shared_examples(name, &block)
      #   @param name [String, Symbol, Module] identifer to use when looking up
      #     this shared group
      #   @param block The block to be eval'd
      # @overload shared_examples(name, metadata, &block)
      #   @param name [String, Symbol, Module] identifer to use when looking up
      #     this shared group
      #   @param metadata [Array<Symbol>, Hash] metadata to attach to this
      #     group; any example group or example with matching metadata will
      #     automatically include this shared example group.
      #   @param block The block to be eval'd
      #
      # Stores the block for later use. The block will be evaluated
      # in the context of an example group via `include_examples`,
      # `include_context`, or `it_behaves_like`.
      #
      # @example
      #   shared_examples "auditable" do
      #     it "stores an audit record on save!" do
      #       expect { auditable.save! }.to change(Audit, :count).by(1)
      #     end
      #   end
      #
      #   RSpec.describe Account do
      #     it_behaves_like "auditable" do
      #       let(:auditable) { Account.new }
      #     end
      #   end
      #
      # @see ExampleGroup.it_behaves_like
      # @see ExampleGroup.include_examples
      # @see ExampleGroup.include_context
      def shared_examples(name, *args, &block)
        top_level = self == ExampleGroup
        if top_level && RSpec::Support.thread_local_data[:in_example_group]
          raise "Creating isolated shared examples from within a context is " \
                "not allowed. Remove `RSpec.` prefix or move this to a " \
                "top-level scope."
        end

        RSpec.world.shared_example_group_registry.add(self, name, *args, &block)
      end
      alias shared_context      shared_examples
      alias shared_examples_for shared_examples

      # @api private
      #
      # Shared examples top level DSL.
      module TopLevelDSL
        # @private
        def self.definitions
          proc do
            def shared_examples(name, *args, &block)
              RSpec.world.shared_example_group_registry.add(:main, name, *args, &block)
            end
            alias shared_context      shared_examples
            alias shared_examples_for shared_examples
          end
        end

        # @private
        def self.exposed_globally?
          @exposed_globally ||= false
        end

        # @api private
        #
        # Adds the top level DSL methods to Module and the top level binding.
        def self.expose_globally!
          return if exposed_globally?
          Core::DSL.change_global_dsl(&definitions)
          @exposed_globally = true
        end

        # @api private
        #
        # Removes the top level DSL methods to Module and the top level binding.
        def self.remove_globally!
          return unless exposed_globally?

          Core::DSL.change_global_dsl do
            undef shared_examples
            undef shared_context
            undef shared_examples_for
          end

          @exposed_globally = false
        end
      end

      # @private
      class Registry
        def add(context, name, *metadata_args, &block)
          unless block
            RSpec.warning "Shared example group #{name} was defined without a "\
                          "block and will have no effect. Please define a "\
                          "block or remove the definition."
          end

          if RSpec.configuration.shared_context_metadata_behavior == :trigger_inclusion
            return legacy_add(context, name, *metadata_args, &block)
          end

          unless valid_name?(name)
            raise ArgumentError, "Shared example group names can only be a string, " \
                                 "symbol or module but got: #{name.inspect}"
          end

          ensure_block_has_source_location(block) { CallerFilter.first_non_rspec_line }
          warn_if_key_taken context, name, block

          metadata = Metadata.build_hash_from(metadata_args)
          shared_module = SharedExampleGroupModule.new(name, block, metadata)
          shared_example_groups[context][name] = shared_module
        end

        def find(lookup_contexts, name)
          lookup_contexts.each do |context|
            found = shared_example_groups[context][name]
            return found if found
          end

          shared_example_groups[:main][name]
        end

      private

        # TODO: remove this in RSpec 4. This exists only to support
        # `config.shared_context_metadata_behavior == :trigger_inclusion`,
        # the legacy behavior of shared context metadata, which we do
        # not want to support in RSpec 4.
        def legacy_add(context, name, *metadata_args, &block)
          ensure_block_has_source_location(block) { CallerFilter.first_non_rspec_line }
          shared_module = SharedExampleGroupModule.new(name, block, {})

          if valid_name?(name)
            warn_if_key_taken context, name, block
            shared_example_groups[context][name] = shared_module
          else
            metadata_args.unshift name
          end

          return if metadata_args.empty?
          RSpec.configuration.include shared_module, *metadata_args
        end

        def shared_example_groups
          @shared_example_groups ||= Hash.new { |hash, context| hash[context] = {} }
        end

        def valid_name?(candidate)
          case candidate
          when String, Symbol, Module then true
          else false
          end
        end

        def warn_if_key_taken(context, key, new_block)
          existing_module = shared_example_groups[context][key]
          return unless existing_module

          old_definition_location = formatted_location existing_module.definition
          new_definition_location = formatted_location new_block
          loaded_spec_files = RSpec.configuration.loaded_spec_files

          if loaded_spec_files.include?(new_definition_location) && old_definition_location == new_definition_location
            RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
              |WARNING: Your shared example group, '#{key}', defined at:
              | #{old_definition_location}
              |was automatically loaded by RSpec because the file name
              |matches the configured autoloading pattern (#{RSpec.configuration.pattern}),
              |and is also being required from somewhere else. To fix this
              |warning, either rename the file to not match the pattern, or
              |do not explicitly require the file.
            WARNING
          else
            RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
              |WARNING: Shared example group '#{key}' has been previously defined at:
              |  #{old_definition_location}
              |...and you are now defining it at:
              |  #{new_definition_location}
              |The new definition will overwrite the original one.
            WARNING
          end
        end

        if RUBY_VERSION.to_f >= 1.9
          def formatted_location(block)
            block.source_location.join(":")
          end
        else # 1.8.7
          # :nocov:
          def formatted_location(block)
            block.source_location.join(":").gsub(/:in.*$/, '')
          end
          # :nocov:
        end

        if Proc.method_defined?(:source_location)
          def ensure_block_has_source_location(_block); end
        else # for 1.8.7
          # :nocov:
          def ensure_block_has_source_location(block)
            source_location = yield.split(':')
            block.extend(Module.new { define_method(:source_location) { source_location } })
          end
          # :nocov:
        end
      end
    end
  end

  instance_exec(&Core::SharedExampleGroup::TopLevelDSL.definitions)
end


def legacy_add(context, name, *metadata_args, &block)
          ensure_block_has_source_location(block) { CallerFilter.first_non_rspec_line }
          shared_module = SharedExampleGroupModule.new(name, block, {})

          if valid_name?(name)
            warn_if_key_taken context, name, block
            shared_example_groups[context][name] = shared_module
          else
            metadata_args.unshift name
          end

          return if metadata_args.empty?
          RSpec.configuration.include shared_module, *metadata_args
        end


def warn_if_key_taken(context, key, new_block)
          existing_module = shared_example_groups[context][key]
          return unless existing_module

          old_definition_location = formatted_location existing_module.definition
          new_definition_location = formatted_location new_block
          loaded_spec_files = RSpec.configuration.loaded_spec_files

          if loaded_spec_files.include?(new_definition_location) && old_definition_location == new_definition_location
            RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
              |WARNING: Your shared example group, '#{key}', defined at:
              | #{old_definition_location}
              |was automatically loaded by RSpec because the file name
              |matches the configured autoloading pattern (#{RSpec.configuration.pattern}),
              |and is also being required from somewhere else. To fix this
              |warning, either rename the file to not match the pattern, or
              |do not explicitly require the file.
            WARNING
          else
            RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
              |WARNING: Shared example group '#{key}' has been previously defined at:
              |  #{old_definition_location}
              |...and you are now defining it at:
              |  #{new_definition_location}
              |The new definition will overwrite the original one.
            WARNING
          end
        end


module RSpec
  module Core
    # @api private
    #
    # Internal container for global non-configuration data.
    class World
      # @private
      attr_reader :example_groups, :filtered_examples, :example_group_counts_by_spec_file

      # Used internally to determine what to do when a SIGINT is received.
      attr_accessor :wants_to_quit

      # Used internally to signify that a SystemExit occurred in
      # `Configuration#load_file_handling_errors`, and thus examples cannot
      # be counted accurately. Specifically, we cannot accurately report
      # "No examples found".
      # @private
      attr_accessor :rspec_is_quitting

      # Used internally to signal that a failure outside of an example
      # has occurred, and that therefore the exit status should indicate
      # the run failed.
      # @private
      attr_accessor :non_example_failure

      def initialize(configuration=RSpec.configuration)
        @wants_to_quit = false
        @rspec_is_quitting = false
        @configuration = configuration
        configuration.world = self
        @example_groups = []
        @example_group_counts_by_spec_file = Hash.new(0)
        prepare_example_filtering
      end

      # @api public
      #
      # Prepares filters so that they apply to example groups when they run.
      #
      # This is a separate method so that filters can be modified/replaced and
      # examples refiltered during a process's lifetime, which can be useful for
      # a custom runner.
      def prepare_example_filtering
        @filtered_examples = Hash.new do |hash, group|
          hash[group] = filter_manager.prune(group.examples)
        end
      end

      # @api private
      #
      # Apply ordering strategy from configuration to example groups.
      def ordered_example_groups
        ordering_strategy = @configuration.ordering_registry.fetch(:global)
        ordering_strategy.order(@example_groups)
      end

      # @api private
      #
      # Reset world to 'scratch' before running suite.
      def reset
        RSpec::ExampleGroups.remove_all_constants
        example_groups.clear
        @sources_by_path.clear if defined?(@sources_by_path)
        @syntax_highlighter = nil
        @example_group_counts_by_spec_file = Hash.new(0)
      end

      # @private
      def filter_manager
        @configuration.filter_manager
      end

      # @private
      def registered_example_group_files
        @example_group_counts_by_spec_file.keys
      end

      # @api private
      #
      # Records an example group.
      def record(example_group)
        @configuration.on_example_group_definition_callbacks.each { |block| block.call(example_group) }
        @example_group_counts_by_spec_file[example_group.metadata[:absolute_file_path]] += 1
      end

      # @private
      def num_example_groups_defined_in(file)
        @example_group_counts_by_spec_file[file]
      end

      # @private
      def shared_example_group_registry
        @shared_example_group_registry ||= SharedExampleGroup::Registry.new
      end

      # @private
      def inclusion_filter
        @configuration.inclusion_filter
      end

      # @private
      def exclusion_filter
        @configuration.exclusion_filter
      end

      # @api private
      #
      # Get count of examples to be run.
      def example_count(groups=example_groups)
        FlatMap.flat_map(groups) { |g| g.descendants }.
          inject(0) { |a, e| a + e.filtered_examples.size }
      end

      # @private
      def all_example_groups
        FlatMap.flat_map(example_groups) { |g| g.descendants }
      end

      # @private
      def all_examples
        FlatMap.flat_map(all_example_groups) { |g| g.examples }
      end

      # @private
      # Traverses the tree of each top level group.
      # For each it yields the group, then the children, recursively.
      # Halts the traversal of a branch of the tree as soon as the passed block returns true.
      # Note that siblings groups and their sub-trees will continue to be explored.
      # This is intended to make it easy to find the top-most group that satisfies some
      # condition.
      def traverse_example_group_trees_until(&block)
        example_groups.each do |group|
          group.traverse_tree_until(&block)
        end
      end

      # @api private
      #
      # Find line number of previous declaration.
      def preceding_declaration_line(absolute_file_name, filter_line)
        line_numbers = descending_declaration_line_numbers_by_file.fetch(absolute_file_name) do
          return nil
        end

        line_numbers.find { |num| num <= filter_line }
      end

      # @private
      def reporter
        @configuration.reporter
      end

      # @private
      def source_from_file(path)
        unless defined?(@sources_by_path)
          RSpec::Support.require_rspec_support 'source'
          @sources_by_path = {}
        end

        @sources_by_path[path] ||= Support::Source.from_file(path)
      end

      # @private
      def syntax_highlighter
        @syntax_highlighter ||= Formatters::SyntaxHighlighter.new(@configuration)
      end

      # @api private
      #
      # Notify reporter of filters.
      def announce_filters
        fail_if_config_and_cli_options_invalid
        filter_announcements = []

        announce_inclusion_filter filter_announcements
        announce_exclusion_filter filter_announcements

        unless filter_manager.empty?
          if filter_announcements.length == 1
            report_filter_message("Run options: #{filter_announcements[0]}")
          else
            report_filter_message("Run options:\n  #{filter_announcements.join("\n  ")}")
          end
        end

        if @configuration.run_all_when_everything_filtered? && example_count.zero? && !@configuration.only_failures?
          report_filter_message("#{everything_filtered_message}; ignoring #{inclusion_filter.description}")
          filtered_examples.clear
          inclusion_filter.clear
        end

        return unless example_count.zero?

        example_groups.clear
        unless rspec_is_quitting
          if filter_manager.empty?
            report_filter_message("No examples found.")
          elsif exclusion_filter.empty? || inclusion_filter.empty?
            report_filter_message(everything_filtered_message)
          end
        end
      end

      # @private
      def report_filter_message(message)
        reporter.message(message) unless @configuration.silence_filter_announcements?
      end

      # @private
      def everything_filtered_message
        "\nAll examples were filtered out"
      end

      # @api private
      #
      # Add inclusion filters to announcement message.
      def announce_inclusion_filter(announcements)
        return if inclusion_filter.empty?

        announcements << "include #{inclusion_filter.description}"
      end

      # @api private
      #
      # Add exclusion filters to announcement message.
      def announce_exclusion_filter(announcements)
        return if exclusion_filter.empty?

        announcements << "exclude #{exclusion_filter.description}"
      end

    private

      def descending_declaration_line_numbers_by_file
        @descending_declaration_line_numbers_by_file ||= begin
          declaration_locations = FlatMap.flat_map(example_groups, &:declaration_locations)
          hash_of_arrays = Hash.new { |h, k| h[k] = [] }

          # TODO: change `inject` to `each_with_object` when we drop 1.8.7 support.
          line_nums_by_file = declaration_locations.inject(hash_of_arrays) do |hash, (file_name, line_number)|
            hash[file_name] << line_number
            hash
          end

          line_nums_by_file.each_value do |list|
            list.sort!
            list.reverse!
          end
        end
      end

      def fail_if_config_and_cli_options_invalid
        return unless @configuration.only_failures_but_not_configured?

        reporter.abort_with(
          "\nTo use `--only-failures`, you must first set " \
          "`config.example_status_persistence_file_path`.",
          1 # exit code
        )
      end

      # @private
      # Provides a null implementation for initial use by configuration.
      module Null
        def self.non_example_failure; end
        def self.non_example_failure=(_); end

        def self.registered_example_group_files
          []
        end

        def self.traverse_example_group_trees_until
        end

        # :nocov:
        def self.example_groups
          []
        end

        def self.all_example_groups
          []
        end
        # :nocov:
      end
    end
  end
end


def descending_declaration_line_numbers_by_file
        @descending_declaration_line_numbers_by_file ||= begin
          declaration_locations = FlatMap.flat_map(example_groups, &:declaration_locations)
          hash_of_arrays = Hash.new { |h, k| h[k] = [] }

          # TODO: change `inject` to `each_with_object` when we drop 1.8.7 support.
          line_nums_by_file = declaration_locations.inject(hash_of_arrays) do |hash, (file_name, line_number)|
            hash[file_name] << line_number
            hash
          end

          line_nums_by_file.each_value do |list|
            list.sort!
            list.reverse!
          end
        end
      end


RSpec::Support.require_rspec_core "bisect/shell_command"
RSpec::Support.require_rspec_core "bisect/example_minimizer"
RSpec::Support.require_rspec_core "bisect/utilities"
RSpec::Support.require_rspec_core "formatters/bisect_progress_formatter"

module RSpec
  module Core
    module Bisect
      # The main entry point into the bisect logic. Coordinates among:
      #   - Bisect::ShellCommand: Generates shell commands to run spec subsets
      #   - Bisect::ExampleMinimizer: Contains the core bisect logic.
      #   - A bisect runner: runs a set of examples and returns the results.
      #   - A bisect formatter: provides progress updates to the user.
      # @private
      class Coordinator
        def self.bisect_with(spec_runner, original_cli_args, formatter)
          new(spec_runner, original_cli_args, formatter).bisect
        end

        def initialize(spec_runner, original_cli_args, formatter)
          @spec_runner   = spec_runner
          @shell_command = ShellCommand.new(original_cli_args)
          @notifier      = Bisect::Notifier.new(formatter)
        end

        def bisect
          repro = start_bisect_runner do |runner|
            minimizer = ExampleMinimizer.new(@shell_command, runner, @notifier)

            gracefully_abort_on_sigint(minimizer)
            minimizer.find_minimal_repro
            minimizer.repro_command_for_currently_needed_ids
          end

          @notifier.publish(:bisect_repro_command, :repro => repro)

          true
        rescue BisectFailedError => e
          @notifier.publish(:bisect_failed, :failure_explanation => e.message)
          false
        ensure
          @notifier.publish(:close)
        end

      private

        def start_bisect_runner(&block)
          klass = @spec_runner.configuration.bisect_runner_class
          klass.start(@shell_command, @spec_runner, &block)
        end

        def gracefully_abort_on_sigint(minimizer)
          trap('INT') do
            repro = minimizer.repro_command_for_currently_needed_ids
            @notifier.publish(:bisect_aborted, :repro => repro)
            exit(1)
          end
        end
      end
    end
  end
end