On Fri, Jul 28, 2006 at 01:57:56AM +0900, Caleb C. wrote:
This works fine with my tests. When running rcov though it creates
infinite recursion in the call to old_get. Has anyone tried anything
of the sort? Is it a bug in rcov?
At a guess, (something is) rcov is also wrapping #get and using the
same name for the old version of the method. At least, that’s always
been the explanation when I’ve encountered these ‘wrapping a method
causes infinite recursion’ problems. Try this way instead, it should
eliminate any possibility that your code is participating in the
recursion.
rcov doesn’t redefine anything, it just uses a trace_func (or the C
equivalent
when rcovrt is available). In theory, running a program through rcov
shouldn’t
change its behavior, but this is the second time I’m told there’s some
sort of
bothersome interference with Rails (I haven’t yet been able to fix the
first
issue, reported by Assaph M.).
I’d love to solve this, but I first need to reproduce the bug; a naïve
attempt
fails, as expected:
$ rcov --text-counts foo.rb
1
foo.rb
|
0
class Foo; def foo; end end |
5
class Bar < Foo |
2
alias_method :old_foo, :foo |
1
def foo; p 1; old_foo end |
5
end |
0
|
0
Bar.new.foo |
1
If you cannot show me your code, please keep a copy of the codebase
exhibiting
the bug. I might send you a modified rcov for you to test, if I can
figure
this out.
Actually, I think I know what is going on: when running under rcov, the
file
holding your Rails test helper is being require()d twice. If I’m right,
it
should be possible to infer what is going on by tracing #require, with
e.g.
module Kernel
req = instance_method(:require)
define_method(:require) do |*a|
puts “-” * 80
puts "Kernel#require " + a.inspect
puts caller.inspect
req.bind(self).call(*a)
end
end
and then looking for the calls where your test file was loaded. Things
should
be easy until that stage. After that, we’d have to see why rcov
introduces a
difference in the second call.
[Thinking as I write] rcov loads the files supplied in the command line
with
Kernel#load, so if you later #require’ any of them, it would be loaded
twice.
Moreover, Rake’s default test loader also works this way; here’s its
source
code:
ARGV.each { |f| load f unless f =~ /^-/ }
If this hunch is correct, the following patch to bin/rcov could save the
day:
diff -rN -u old-tmp/bin/rcov new-tmp/bin/rcov
— old-tmp/bin/rcov 2006-07-27 21:50:33.000000000 +0200
+++ new-tmp/bin/rcov 2006-07-27 21:50:33.000000000 +0200
@@ -450,7 +450,7 @@
if options.replace_prog_name
$0 = File.basename(File.expand_path(prog))
end
Rake would also have to be changed, but I’d like to make sure the
modification
is appropriate before applying it to rcov and sending jweirich a patch.
old_get=instance_method(:get)
define_method(:get) do |*args|
old_get[*args]
if @response.success?
assert_valid_markup
end
end
This trick was originated by Mauricio F., as far as I know.
It was most probably discovered by some anonymous Japanese Rubyist
before I
popularized it to some extent, though