module TransactionalTest # Wraps each test in a transaction that is always rolled back. The `result` # dance is needed because Sequel's transaction method isn't good at returning # the result of the block. def run(runner) result = nil DB.transaction(:rollback => :always) { result = super } result end end class MiniTest::Spec include TransactionalTest class << self # Finds the top-most test, that is a test that directly inherits from # MiniTest::Spec. # Used by the runner to group tests in to logical blocks. def parent_suite a = ancestors.take_while { |a| a != MiniTest::Spec }.select { |a| Class === a } a.last end def start(&block) @start_hook = block end def finish(&block) @finish_hook = block end def _hooks_run @_hooks_run ||= [] end def _run_start_hook _run_start_finish_hook(@start_hook, :start) end def _run_finish_hook if _hooks_run.include?(:start) _run_start_finish_hook(@finish_hook, :finish) end end def _run_start_finish_hook(hook, label) _hooks_run << label hook.call if hook end end end # This relies on the test cases supporting the ::start & ::finish hooks # as well as the ::parent_suite method. class StartFinishRunner < MiniTest::Unit def _run_suites(suites, type) linebreak = "" results = [] grouped = suites.group_by { |suite| suite.parent_suite } grouped.delete(nil) names = grouped.keys.map(&:to_s) max_name_length = names.map(&:length).max grouped.each do |master, tests| output.print(output.bold("#{linebreak}#{master.to_s.ljust(max_name_length, " ")} ")) DB.synchronize do begin master._run_start_hook results.concat super(tests, type) ensure master._run_finish_hook end end linebreak = "\n" end results end end # I find the stream of green dots & yellow "S"s a little too strident. # Just give me red for errors. module Minitest class PlainColorize < Minitest::Colorize def print(string = nil) return stream.print if string.nil? case string when 'E', 'F' stream.print error(string) when 'S' stream.print grey(string) else stream.print string end end def error(string) tint([1, 31], string) end def bold(string) tint(1, string) end def grey(string) tint([30, 1], string) end def tint(color, string) return string unless color_enabled? effects = Array(color).map { |c| "\e[#{c}m"}.join "#{effects}#{string}\e[0m" end # I want to be able to use these [:red, :green, :yellow].each { |m| public m } end end MiniTest::Unit.output = MiniTest::PlainColorize.new