diff options
-rw-r--r-- | doc/README_RCOV_PLUGIN | 86 | ||||
-rw-r--r-- | lib/tasks/rails_rcov.rake | 150 |
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 |