module Minitest::SuiteCallbacks
TODO: Make it work when we have a base level before_suite and a context/describe
It just doesn’t work at all with contexts & suite-wide setup
Public Class Methods
extended(base)
click to toggle source
# File lib/minitest/suite_callbacks.rb, line 6 def self.extended(base) class << base attr_reader :sandbox attr_accessor :counter # Define before_suite on the test class context def before_suite(&before_suite_proc) # Setup state before suite context = self singleton_class.class_eval do original_singleton_run = instance_method(:run) # Wrap the run method on the singleton class of the test class define_method :run do |*args, &block| # TODO this is kind of hacky; it only runs before_suite once # I don't think this will support other use cases (e.g. multiple before_suites/nested before_suites) context.instance_eval do if @sandbox.nil? @sandbox = new('sandbox') @sandbox.instance_eval &before_suite_proc end end original_singleton_run.bind(self).call(*args, &block) end end # TODO what if we call before_suite multiple times? original_instance_run = instance_method(:run) define_method :run do |*args, &block| context.transfer_sandbox_state_to(self) original_instance_run.bind(self).call(*args, &block) end end # TODO: because of how Minitest separates its suites, this method gets called after EACH suite, # not after all related suites are finished def after_suite(&after_suite_proc) @counter = 0 context = self singleton_class.class_eval do original_singleton_run = instance_method(:run) define_method :run do |*args, &block| original_singleton_run.bind(self).call(*args, &block) context.instance_eval do @counter += 1 if has_run_all_related_suites? @sandbox.instance_eval &after_suite_proc end end end end end def has_run_all_related_suites? # Get the number of subclasses + the class itself @counter == descendant_count + 1 end def descendant_count ObjectSpace.each_object(::Class).select{|k| k < self}.size end def transfer_sandbox_state_to(dest_context) # TODO: generate these ivs_to_skip = [:@NAME, :@assertions, :@failures] iv_map = {} @sandbox.instance_variables.each do |iv| next if ivs_to_skip.include?(iv) iv_map[iv] = @sandbox.instance_variable_get(iv.to_sym) end dest_context.instance_eval do iv_map.each do |k, v| instance_variable_set k, v end end end end end