aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/README_RCOV_PLUGIN86
-rw-r--r--lib/tasks/rails_rcov.rake150
2 files changed, 236 insertions, 0 deletions
diff --git a/doc/README_RCOV_PLUGIN b/doc/README_RCOV_PLUGIN
new file mode 100644
index 0000000..eb9d84c
--- /dev/null
+++ b/doc/README_RCOV_PLUGIN
@@ -0,0 +1,86 @@
+ = rails_rcov plugin for Rails
+
+rails_rcov provides easy-to-use Rake tasks to determine the code coverage of
+your unit, functional, and integration tests using Mauricio Fernandez's rcov
+tool.
+
+== Installation
+
+First, install rcov from Mauricio's web site
+[http://eigenclass.org/hiki.rb?rcov]. Make sure it's on your system path, so
+that typing +rcov+ on the command line actually runs it. THIS PLUGIN DOESN'T DO
+ANYTHING BESIDES GENERATE ERRORS UNLESS YOU INSTALL RCOV FIRST. RCOV CONTAINS
+ALL THE MAGIC, THIS PLUGIN JUST RUNS IT.
+
+Second, install this plugin. If your project is source-controlled by Subversion
+(which it should be, really), the easiest way to install this is via Rails'
+plugin script:
+
+ ./script/plugin install -x http://svn.codahale.com/rails_rcov
+
+If you're not using Subversion, or if you don't want it adding
+<tt>svn:externals</tt> in your project, remove the <tt>-x</tt> switch:
+
+ ./script/plugin install http://svn.codahale.com/rails_rcov
+
+== Usage
+
+For each <tt>test:blah</tt> task you have for your Rails project, rails_rcov
+adds two more: <tt>test:blah:rcov</tt> and <tt>test:blah:clobber_rcov</tt>.
+
+Running <tt>rake test:units:rcov</tt>, for example, will run your unit tests
+through rcov and write the code coverage reports to
+<tt>your_rails_app/coverage/units</tt>.
+
+Running <tt>test:units:clobber_rcov</tt> will erase the generated report for the
+unit tests.
+
+Each rcov task takes two optional parameters: RCOV_PARAMS, whose argument is
+passed along to rcov, and SHOW_ONLY, which limits the files displayed in the
+report.
+
+RCOV_PARAMS:
+ # sort by coverage
+ rake test:units:rcov RCOV_PARAMS="--sort=coverage"
+
+ # show callsites and hide fully covered files
+ rake test:units:rcov RCOV_PARAMS="--callsites --only-uncovered"
+
+Check the rcov documentation for more details.
+
+SHOW_ONLY is a comma-separated list of the files you'd like to see. Right now
+there are four types of files rake_rcov recognizes: models, helpers,
+controllers, and lib. These can be abbreviated to their first letters:
+
+ # only show files from app/models
+ rake test:units:rcov SHOW_ONLY=models
+
+ # only show files from app/helpers and app/controllers
+ rake test:units:rcov SHOW_ONLY=helpers,controllers
+
+ # only show files from app/helpers and app/controllers, with less typing
+ rake test:units:rcov SHOW_ONLY=h,c
+
+Please note that rails_rcov has only been tested with a Bash shell, and any
+other environment could well explode in your face. If you're having trouble
+getting this to work on Windows, please take the time to figure out what's not
+working. Most of the time it boils down to the different ways the Window shell
+and the Bash shell escape metacharacters. Play around with the way rcov_rake
+escapes data (like on line 73, or 78) and send me a fix. I don't have a working
+Windows environment anymore, so leaving it up to me won't solve anything. ;-)
+
+== Resources
+
+=== Subversion
+
+* http://svn.codahale.com/rails_rcov
+
+=== Blog
+
+* http://blog.codahale.com
+
+== Credits
+
+Written by Coda Hale <coda.hale@gmail.com>. Thanks to Nils Franzen for a Win32
+escaping patch. Thanks to Alex Wayne for suggesting how to make SHOW_ONLY not be
+useless. \ No newline at end of file
diff --git a/lib/tasks/rails_rcov.rake b/lib/tasks/rails_rcov.rake
new file mode 100644
index 0000000..4fd798d
--- /dev/null
+++ b/lib/tasks/rails_rcov.rake
@@ -0,0 +1,150 @@
+# This File Uses Magic
+# ====================
+# Here's an example of how this file works. As an example, let's say you typed
+# this into your terminal:
+#
+# $ rake --tasks
+#
+# The rake executable goes through all the various places .rake files can be,
+# accumulates them all, and then runs them. When this file is loaded by Rake,
+# it iterates through all the tasks, and for each task named 'test:blah' adds
+# test:blah:rcov and test:blah:rcov_clobber.
+#
+# So you've seen all the tasks, and you type this into your terminal:
+#
+# $ rake test:units:rcov
+#
+# Rake does the same thing as above, but it runs the test:units:rcov task, which
+# pretty much just does this:
+#
+# $ ruby [this file] [the test you want to run] [some options]
+#
+# Now this file is run via the Ruby interpreter, and after glomming up the
+# options, it acts just like the Rake executable, with a slight difference: it
+# passes all the arguments to rcov, not ruby, so all your unit tests get some
+# rcov sweet loving.
+
+if ARGV.grep(/--run-rake-task=/).empty?
+ # Define all our Rake tasks
+
+ require 'rake/clean'
+ require 'rcov/rcovtask'
+
+ def to_rcov_task_sym(s)
+ s = s.gsub(/(test:)/,'')
+ s.empty? ? nil : s.intern
+ end
+
+ def to_rcov_task_name(s)
+ s = s.gsub(/(test:)/,'')
+ s =~ /s$/i ? s[0..-2] : s
+ end
+
+ def new_rcov_task(test_name)
+ output_dir = "./coverage/#{test_name.gsub('test:','')}"
+ CLOBBER.include(output_dir)
+
+ # Add a task to run the rcov process
+ desc "Run all #{to_rcov_task_name(test_name)} tests with Rcov to measure coverage"
+ task :rcov => [:clobber_rcov] do |t|
+ run_code = '"' << File.expand_path(__FILE__) << '"'
+ run_code << " --run-rake-task=#{test_name}"
+
+ params = String.new
+ if ENV['RCOV_PARAMS']
+ params << ENV['RCOV_PARAMS']
+ end
+
+ # rake test:units:rcov SHOW_ONLY=models,controllers,lib,helpers
+ # rake test:units:rcov SHOW_ONLY=m,c,l,h
+ if ENV['SHOW_ONLY']
+ show_only = ENV['SHOW_ONLY'].to_s.split(',').map{|x|x.strip}
+ if show_only.any?
+ reg_exp = []
+ for show_type in show_only
+ reg_exp << case show_type
+ when 'm', 'models' : 'app\/models'
+ when 'c', 'controllers' : 'app\/controllers'
+ when 'h', 'helpers' : 'app\/helpers'
+ when 'l', 'lib' : 'lib'
+ else
+ show_type
+ end
+ end
+ reg_exp.map!{ |m| "(#{m})" }
+ params << " -x \\\"^(?!#{reg_exp.join('|')})\\\""
+ end
+ end
+
+ unless params.empty?
+ run_code << " --rcov-params=\"#{params}\""
+ end
+
+ ruby run_code
+ end
+
+ # Add a task to clean up after ourselves
+ desc "Remove Rcov reports for #{to_rcov_task_name(test_name)} tests"
+ task :clobber_rcov do |t|
+ rm_r output_dir, :force => true
+ end
+
+ # Link our clobber task to the main one
+ task :clobber => [:clobber_rcov]
+ end
+
+ test_tasks = Rake::Task.tasks.select{ |t| t.comment && t.name =~ /^test/ }
+ for test_task in test_tasks
+ namespace :test do
+ if sym = to_rcov_task_sym(test_task.name)
+ namespace sym do
+ new_rcov_task(test_task.name)
+ end
+ end
+ end
+ end
+else
+ # Load rake tasks, hijack ruby, and redirect the task through rcov
+ require 'rubygems'
+ require 'rake'
+
+ module RcovTestSettings
+ class << self
+ attr_accessor :output_dir, :options
+ def to_params
+ "-o \"#{@output_dir}\" -T -x \"rubygems/*,rcov*\" --rails #{@options}"
+ end
+ end
+
+ # load options and arguments from command line
+ unless (cmd_line = ARGV.grep(/--rcov-params=/)).empty?
+ @options = cmd_line.first.gsub(/--rcov-params=/, '')
+ end
+ end
+
+ def is_windows?
+ processor, platform, *rest = RUBY_PLATFORM.split("-")
+ platform == 'mswin32'
+ end
+
+ # intercept what Rake *would* be doing with Ruby, and send it through Rcov instead
+ module RakeFileUtils
+ alias :ruby_without_rcov :ruby
+ def ruby(*args, &block)
+ cmd = (is_windows? ? 'rcov.cmd' : 'rcov') << " #{RcovTestSettings.to_params} #{args}"
+ status = sh(cmd, {}, &block)
+ puts "View the full results at <file://#{RcovTestSettings.output_dir}/index.html>"
+ return status
+ end
+ end
+
+ # read the test name and execute it (through Rcov)
+ unless (cmd_line = ARGV.grep(/--run-rake-task=/)).empty?
+ test_name = cmd_line.first.gsub(/--run-rake-task=/,'')
+ ARGV.clear; ARGV << test_name
+ RcovTestSettings.output_dir = File.expand_path("./coverage/#{test_name.gsub('test:','')}")
+ Rake.application.run
+ else
+ raise "No test to execute!"
+ end
+end \ No newline at end of file