fog--fog/spec/compact_progress_bar_format...

196 lines
7.2 KiB
Ruby

# Copyright (c) 2008 Nicholas A. Evans
# http://ekenosen.net/nick/devblog/2008/12/better-progress-bar-for-rspec/
#
# With some tweaks (slow spec profiler, growl support)
# By Nick Zadrozny
# http://gist.github.com/71340
#
# Further tweaks (formatador, elapsed time instead of eta)
# By geemus (Wesley Beary)
# http://gist.github.com/266221
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require 'spec/runner/formatter/base_text_formatter'
require "rubygems"
require 'formatador'
module Spec
module Runner
module Formatter
class CompactProgressBarFormatter < BaseTextFormatter
# Threshold for slow specs, in seconds.
# Anything that takes longer than this will be printed out
# It would be great to get this down to 0.5 or less...
SLOW_SPEC_THRESHOLD = 2.0
# Keep track the slowest specs and print a report at the end
SLOW_SPEC_REPORT = 3
attr_reader :total, :current
def start(example_count)
@current = 0
@started_at = Time.now
@total = example_count
@error_state = :all_passing
@slow_specs = []
@formatador = Formatador.new
@formatador.display_line
end
def example_started(example)
super
@start_time = Time.now
end
def example_passed(example)
elapsed = Time.now - @start_time
profile_example(example_group.description, example.description, elapsed)
increment
end
# third param is optional, because earlier versions of rspec sent only two args
def example_pending(example, message, pending_caller=nil)
immediately_dump_pending(example.description, message, pending_caller)
mark_error_state_pending
increment
end
def example_failed(example, counter, failure)
immediately_dump_failure(counter, failure)
notify_failure(counter, failure)
mark_error_state_failed
increment
end
def start_dump
@formatador.display_line("\n")
report_slow_specs
end
def dump_failure(*args)
# no-op; we summarized failures as we were running
end
def method_missing(sym, *args)
# ignore
end
def notify(title, message, priority)
title = title.gsub(/\s+/, ' ').gsub(/"/,'\"').gsub(/'/, "\'")
message = message.gsub(/\s+/, ' ').gsub(/"/,'\"').gsub(/'/, "\'").gsub(/`/,'\`')
notify_command = case RUBY_PLATFORM
when /darwin/
"test -x `which growlnotify` && growlnotify -n autotest -p #{priority} -m \"#{message}\" \"#{title}\""
when /linux/
"test -x `which notify-send` && notify-send \"#{title}\" \"#{message}\""
end
# puts notify_command # use this for debugging purposes
system notify_command if notify_command
end
def notify_failure(counter, failure)
notify failure.header, failure.exception.message, 2
end
# stolen and slightly modified from BaseTextFormatter#dump_failure
def immediately_dump_failure(counter, failure)
@formatador.redisplay("#{' ' * progress_bar.length}\n")
@formatador.redisplay("[red]#{counter.to_s})[/]")
@formatador.display_line("[red]#{failure.header}[/]")
@formatador.indent do
@formatador.display_line("[red]#{failure.exception.message}[/]")
@formatador.display_line
failure.exception.backtrace.each do |line|
@formatador.display_line("[red]#{line}[/]")
end
@formatador.display_line
end
end
# stolen and modified from BaseTextFormatter#dump_pending
def immediately_dump_pending(desc, msg, called_from)
@formatador.indent do
@formatador.redisplay("#{' ' * progress_bar.length}\r")
@formatador.display_line("[yellow]PENDING SPEC:[/] #{desc} (#{msg})\n")
end
# output.puts " Called from #{called_from}" if called_from
end
def increment
@current += 1
@formatador.redisplay(progress_bar)
end
def mark_error_state_failed
@error_state = :some_failed
end
def mark_error_state_pending
@error_state = :some_pending unless @error_state == :some_failed
end
def progress_bar
color = case @error_state
when :some_failed
'red'
when :some_pending
'yellow'
else
'green'
end
ratio = "#{(' ' * (@total.to_s.size - @current.to_s.size))}#{@current}/#{@total}"
fraction = "[#{color}]#{(' ' * (@total.to_s.size - @current.to_s.size))}#{@current}/#{@total}[/]"
percent = @current.to_f / @total.to_f
progress = "[_white_]|[/][#{color}][_#{color}_]#{'*' * (percent * 50).ceil}[/]#{' ' * (50 - (percent * 50).ceil)}[_white_]|[/]"
microseconds = Time.now - @started_at
minutes = (microseconds / 60).round.to_s
seconds = (microseconds % 60).round.to_s
elapsed = "#{minutes}:#{'0' if seconds.size < 2}#{seconds}"
[fraction, progress, elapsed, ''].join(' ')
end
def profile_example(group, example, elapsed)
@slow_specs = (@slow_specs + [[elapsed, group, example]]).sort.reverse[0, SLOW_SPEC_REPORT]
print_warning_if_really_slow(group, example, elapsed)
end
def print_warning_if_really_slow(group, example, elapsed)
if elapsed > SLOW_SPEC_THRESHOLD
@formatador.indent do
@formatador.redisplay("#{' ' * progress_bar.length}\r")
@formatador.display_line("[yellow]SLOW SPEC (#{sprintf("%.4f", elapsed)})[/]: #{group} #{example}\n")
end
end
end
def report_slow_specs
@formatador.display_line("[yellow]Top #{@slow_specs.size} slowest specs:[/]")
@slow_specs.each do |elapsed, group, example|
@formatador.display_line("[yellow] #{yellow(sprintf('%.4f', elapsed))} #{group} #{example}[/]")
end
end
end
end
end
end