Michal Suchanek
12/21/2007 10:32:00 PM
On 21/12/2007, Eric Hodel <drbrain@segment7.net> wrote:
> On Dec 21, 2007, at 05:50 AM, Charles Oliver Nutter wrote:
> > Eric Hodel wrote:
> >> On Dec 20, 2007, at 21:45 PM, Daniel Berger wrote:
> >>> I follow the same pattern in the tests, but it doesn't raise the
> >>> expected error. Any ideas?
> >> Since the GC is conservative, references may exist longer than you
> >> expect because the item that should be collected is still
> >> referenced from the stack. I don't know of an easy way around this.
> >
> > This is probably the largest reason why a weakref suite will be a
> > little tricky. My best recommendation would be to loop calling
> > GC.start until the reference gets collected; perhaps with an upper
> > count... "if we reach 1000 iterations and it's not collected, it
> > isn't working".
>
> If it isn't collected after 1, I doubt it will be collected after
> 1000. You'd have better luck manipulating the stack (calling methods
> recursively that eventually allocate things), but you're still not
> guaranteed that any object will be collected when you want with ruby
> 1.8 or 1.9.
>
>
Yes, the behavior looks very non-deterministic from the outside, it
even depends on naming of the tests. I had better luck making it work
with 1.8 (works as is) but it won't work with 1.9. The first test that
tests the weakref dies does not succeed, and the second does.
This one works for me but it likely depends on exact state of the heap
or something like that which is system specific:
require 'test/unit'
require 'weakref'
class TC_WeakRef < Test::Unit::TestCase
def setup
@ref = nil
@str = "hello"
GC.enable
end
# Fails in 1.9 because WeakRef does not have inspect,
# and it pretends to be String
def test_weakref_constructor
assert_respond_to(WeakRef, :new)
assert_nothing_raised{ @ref = WeakRef.new(@str) }
assert_kind_of(WeakRef, @ref)
end
# TODO: Figure out why last test fails
# somehow using the string makes a reference somewhere
def test_weakref_2
str = @str.dup
assert_nothing_raised{ @ref = WeakRef.new(@str) }
assert_equal(true, @ref.weakref_alive?)
assert_equal str, @ref
assert_nothing_raised{ GC.start }
assert_equal(true, @ref.weakref_alive?)
assert_equal str, @ref
assert_nothing_raised{ @str = nil }
assert_equal(true, @ref.weakref_alive?)
assert_equal str, @ref
assert_nothing_raised{ GC.start }
#assert_equal(false, @ref.weakref_alive?)
#assert_raise(WeakRef::RefError){ @str = @ref * 3 }
end
def test_weakref_is_alive_basic
assert_nothing_raised{ @ref = WeakRef.new(@str) }
assert_respond_to(@ref, :weakref_alive?)
end
# TODO: Figure out why last test does not fail
def test_weakref_is_alive
assert_nothing_raised{ @ref = WeakRef.new(@str) }
assert_equal(true, @ref.weakref_alive?)
assert_nothing_raised{ GC.start }
assert_equal(true, @ref.weakref_alive?)
assert_nothing_raised{ @str = nil }
assert_equal(true, @ref.weakref_alive?)
assert_nothing_raised{ GC.start }
assert_equal(false, @ref.weakref_alive?)
assert_raise(WeakRef::RefError){ @str = @ref * 3 }
end
def teardown
@str = nil
@ref = nil
end
end