class RSpec::Core::Bisect::ExampleMinimizer
@private Contains the core bisect logic. Searches for examples we can ignore by repeatedly running different subsets of the suite.
Constants
- ExampleRange
@private Convenience class for describing a subset of the candidate examples
Attributes
all_example_ids[R]
failed_example_ids[R]
remaining_ids[RW]
runner[R]
shell_command[R]
Public Class Methods
new(shell_command, runner, notifier)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 13 def initialize(shell_command, runner, notifier) @shell_command = shell_command @runner = runner @notifier = notifier end
Public Instance Methods
bisect(candidate_ids)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 33 def bisect(candidate_ids) notify(:bisect_dependency_check_started) if get_expected_failures_for?([]) notify(:bisect_dependency_check_failed) self.remaining_ids = [] return end notify(:bisect_dependency_check_passed) bisect_over(candidate_ids) end
bisect_over(candidate_ids)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 45 def bisect_over(candidate_ids) return if candidate_ids.one? notify( :bisect_round_started, :candidate_range => example_range(candidate_ids), :candidates_count => candidate_ids.size ) slice_size = (candidate_ids.length / 2.0).ceil lhs, rhs = candidate_ids.each_slice(slice_size).to_a ids_to_ignore, duration = track_duration do [lhs, rhs].find do |ids| get_expected_failures_for?(remaining_ids - ids) end end if ids_to_ignore self.remaining_ids -= ids_to_ignore notify( :bisect_round_ignoring_ids, :ids_to_ignore => ids_to_ignore, :ignore_range => example_range(ids_to_ignore), :remaining_ids => remaining_ids, :duration => duration ) bisect_over(candidate_ids - ids_to_ignore) else notify( :bisect_round_detected_multiple_culprits, :duration => duration ) bisect_over(lhs) bisect_over(rhs) end end
currently_needed_ids()
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 83 def currently_needed_ids remaining_ids + failed_example_ids end
find_minimal_repro()
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 19 def find_minimal_repro prep _, duration = track_duration do bisect(non_failing_example_ids) end notify(:bisect_complete, :duration => duration, :original_non_failing_count => non_failing_example_ids.size, :remaining_count => remaining_ids.size) remaining_ids + failed_example_ids end
repro_command_for_currently_needed_ids()
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 87 def repro_command_for_currently_needed_ids return shell_command.repro_command_from(currently_needed_ids) if remaining_ids "(Not yet enough information to provide any repro command)" end
Private Instance Methods
abort_if_ordering_inconsistent(results)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 158 def abort_if_ordering_inconsistent(results) expected_order = all_example_ids & results.all_example_ids return if expected_order == results.all_example_ids raise BisectFailedError, "\n\nThe example ordering is inconsistent. " \ "`--bisect` relies upon consistent ordering (e.g. by passing " \ "`--seed` if you're using random ordering) to work properly." end
example_range(ids)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 106 def example_range(ids) ExampleRange.new( non_failing_example_ids.find_index(ids.first) + 1, non_failing_example_ids.find_index(ids.last) + 1 ) end
get_expected_failures_for?(ids)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 138 def get_expected_failures_for?(ids) ids_to_run = ids + failed_example_ids notify( :bisect_individual_run_start, :command => shell_command.repro_command_from(ids_to_run), :ids_to_run => ids_to_run ) results, duration = track_duration { runner.run(ids_to_run) } notify(:bisect_individual_run_complete, :duration => duration, :results => results) abort_if_ordering_inconsistent(results) (failed_example_ids & results.failed_example_ids) == failed_example_ids end
non_failing_example_ids()
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 134 def non_failing_example_ids @non_failing_example_ids ||= all_example_ids - failed_example_ids end
notify(*args)
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 167 def notify(*args) @notifier.publish(*args) end
prep()
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 113 def prep notify(:bisect_starting, :original_cli_args => shell_command.original_cli_args, :bisect_runner => runner.class.name) _, duration = track_duration do original_results = runner.original_results @all_example_ids = original_results.all_example_ids @failed_example_ids = original_results.failed_example_ids @remaining_ids = non_failing_example_ids end if @failed_example_ids.empty? raise BisectFailedError, "\n\nNo failures found. Bisect only works " \ "in the presence of one or more failing examples." else notify(:bisect_original_run_complete, :failed_example_ids => failed_example_ids, :non_failing_example_ids => non_failing_example_ids, :duration => duration) end end
track_duration() { || ... }
click to toggle source
# File lib/rspec/core/bisect/example_minimizer.rb, line 153 def track_duration start = ::RSpec::Core::Time.now [yield, ::RSpec::Core::Time.now - start] end