Skip to content

Instantly share code, notes, and snippets.

@agile
Created September 17, 2010 02:27
Show Gist options
  • Save agile/583551 to your computer and use it in GitHub Desktop.
Save agile/583551 to your computer and use it in GitHub Desktop.
# 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/266222
#
# Further tweaks (Rspec2)
# by agile (Mike Vincent)
# http://gist.github.com/583551
#
# 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 'rspec/core/formatters/base_text_formatter'
require "rubygems"
require 'formatador'
module RSpec
module Core
module Formatters
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)
immediately_dump_pending(example)
mark_error_state_pending
increment
end
#def example_failed(example, counter, failure)
def example_failed(example)
if example.pending? #|| !example.metadata[:execution_result][:exception_encoutered]
example_pending(example)
else
immediately_dump_failure(example)
notify_failure(@current, example)
mark_error_state_failed
increment
end
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)
# I already have something that does this, that I like better..
#
# title = title.to_s.gsub(/\s+/, ' ').gsub(/"/,'\"').gsub(/'/, "\'")
# message = message.to_s.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.full_description, failure.metadata[:exception_encountered], 2)
end
# stolen and slightly modified from BaseTextFormatter#dump_failure
def immediately_dump_failure(example)
@formatador.redisplay("#{' ' * progress_bar.length}\n")
@formatador.display_line("[red]#{@current}) FAIL: #{example.full_description}#{'('+example.metadata[:execution_result][:exception_encoutered].to_s + ')' if example.metadata[:execution_result][:exception_encoutered]}[/]")
@formatador.indent do
@formatador.display_line("[red]# #{format_caller example.metadata[:location]}[/]")
@formatador.display_line
end
end
# stolen and modified from BaseTextFormatter#dump_pending
def immediately_dump_pending(example)
@formatador.indent do
@formatador.redisplay("#{' ' * progress_bar.length}\r")
@formatador.display_line("[yellow]PENDING SPEC:[/] #{example.full_description}")
@formatador.indent do
@formatador.display_line("[blue]# #{example.metadata[:execution_result][:pending_message]}[/]") if example.metadata[:execution_result][:pending_message]
@formatador.display_line("[blue]# #{format_caller example.metadata[:location]}[/]") if example.metadata[:location]
end
end
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment