Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created February 13, 2015 01:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenderlove/fba8eaf2b2e3d84d77c5 to your computer and use it in GitHub Desktop.
Save tenderlove/fba8eaf2b2e3d84d77c5 to your computer and use it in GitHub Desktop.
require 'coverage'
require 'json'
# This must be run with this patch applied:
# https://bugs.ruby-lang.org/issues/10816
Coverage.start
require 'minitest'
class Minitest::Runnable
LOG = File.open('run_log.txt', 'w')
Minitest.after_run { LOG.close }
class << self
alias :old_run_one_method :run_one_method
def run_one_method klass, method_name, reporter
before = Coverage.peek_result
old_run_one_method klass, method_name, reporter
after = Coverage.peek_result
LOG.puts JSON.dump [ klass.name, method_name.to_s, before, after ]
end
end
end
require 'rugged'
require 'set'
require 'json'
require 'shellwords'
repo = Rugged::Repository.new '.'
lines_to_run = Set.new
repo.index.diff.each_patch { |patch|
delta = patch.delta
file = delta.old_file[:path]
patch.each_hunk { |hunk|
hunk.each_line { |line|
if line.line_origin == :addition
line = if line.new_lineno == -1
line.old_lineno
else
line.new_lineno
end
lines_to_run << [file, line]
end
}
}
}
def diff before, after
r = after.each_with_object({}) do |(k,v), res|
cov = v.zip(before[k]).map do |line_after, line_before|
if line_after
line_after - line_before
else
line_after
end
end
res[k] = cov
end
r.delete_if { |_, v| v.all? { |line| line.nil? || line == 0 } }
r
end
cov_map = Hash.new { |h, file|
h[file] = Hash.new { |i, line|
i[line] = []
}
}
File.open('run_log.txt') do |f|
f.each_line do |line|
klass, method, before, after = JSON.parse line
delta = diff before, after
delta.each_pair do |file, lines|
file_map = cov_map[file]
lines.each_with_index do |val, i|
next unless val && val > 0
file_map[i + 1] << [klass, method]
end
end
end
end
res = lines_to_run.flat_map do |file, line|
cov_map[File.expand_path(file)][line].map do |klass, method|
"#{klass}##{method}"
end
end
puts Shellwords.escape("/#{res.join('|')}/")
@tenderlove
Copy link
Author

hmmm... I get an error: undefined method 'after' for RSpecLogger:Module

I guess there is no after method available on that module yet (which makes sense). Where should I look for docs on how to do this?

@tenderlove
Copy link
Author

Never mind, I figured it out. Thanks!!

require 'coverage'
require 'json'
require 'rspec'

LOG = File.open('run_log.txt', 'w')
Coverage.start

RSpec.configuration.after(:suite) { LOG.close }

RSpec.configuration.around(:example) do |example|
  before = Coverage.peek_result
  example.call
  after = Coverage.peek_result
  LOG.puts JSON.dump [ example.full_description, before, after ]
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment