Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > First stab at a weakref test suite

Reply
Thread Tools

First stab at a weakref test suite

 
 
Daniel Berger
Guest
Posts: n/a
 
      12-21-2007
Hi all,

I decided to take a stab at creating a minimal test suite for WeakRef
(based on a post by Charles Oliver Nutter for JRuby). The only problem
is that I get two unexpected failures. I'm not sure if it's Test::Unit
fighting with me or what.

Consider the following example:

require 'weakref'
str = 'hello'
ref = WeakRef.new(str)

p ref 'hello'
GC.start
p ref 'hello'
str = nil
p ref # 'hello'
GC.start
p ref # error

I follow the same pattern in the tests, but it doesn't raise the
expected error. Any ideas?

Thanks,

Dan

# tc_weakref.rb
require 'test/unit'
require 'weakref'

class TC_WeakRef < Test::Unit::TestCase
def setup
@ref = nil
@str = 'hello'
GC.enable
end

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
def test_weakref
assert_nothing_raised{ @ref = WeakRef.new(@str) }
assert_equal('hello', @ref)

assert_nothing_raised{ GC.start }
assert_equal('hello', @ref)

assert_nothing_raised{ @str = nil }
assert_equal('hello', @ref)

assert_nothing_raised{ GC.start }
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 fails
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?)
end

def teardown
@str = nil
@ref = nil
end
end

 
Reply With Quote
 
 
 
 
Eric Hodel
Guest
Posts: n/a
 
      12-21-2007
On Dec 20, 2007, at 21:45 PM, Daniel Berger wrote:
> Hi all,
>
> I decided to take a stab at creating a minimal test suite for
> WeakRef (based on a post by Charles Oliver Nutter for JRuby). The
> only problem is that I get two unexpected failures. I'm not sure if
> it's Test::Unit fighting with me or what.
>
> Consider the following example:
>
> require 'weakref'
> str = 'hello'
> ref = WeakRef.new(str)
>
> p ref 'hello'
> GC.start
> p ref 'hello'
> str = nil
> p ref # 'hello'
> GC.start
> p ref # error
>
> 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.

 
Reply With Quote
 
 
 
 
Charles Oliver Nutter
Guest
Posts: n/a
 
      12-21-2007
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".

- Charlie

 
Reply With Quote
 
Eric Hodel
Guest
Posts: n/a
 
      12-21-2007
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.

 
Reply With Quote
 
Michal Suchanek
Guest
Posts: n/a
 
      12-21-2007
On 21/12/2007, Eric Hodel <(E-Mail Removed)> 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

 
Reply With Quote
 
Daniel Berger
Guest
Posts: n/a
 
      12-22-2007


On Dec 21, 6:50 am, Charles Oliver Nutter <(E-Mail Removed)>
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".


I took a look at the Python weakref test suite. I quickly realized
that it appeared to be a richer interface. Maybe that's part of the
problem - the interface we have isn't testable. Take a look here:

http://www.python.org/doc/2.4/lib/module-weakref.html

Then again, maybe I'm way off base. Anyway, I think we should at least
take a look at it and see if we want to steal any ideas from it. The
corresponding test file is test_weakref.py, btw.

Regards,

Dan

 
Reply With Quote
 
Michal Suchanek
Guest
Posts: n/a
 
      12-22-2007
On 22/12/2007, Daniel Berger <(E-Mail Removed)> wrote:

> I took a look at the Python weakref test suite. I quickly realized
> that it appeared to be a richer interface. Maybe that's part of the
> problem - the interface we have isn't testable. Take a look here:
>
> http://www.python.org/doc/2.4/lib/module-weakref.html
>
> Then again, maybe I'm way off base. Anyway, I think we should at least
> take a look at it and see if we want to steal any ideas from it. The
> corresponding test file is test_weakref.py, btw.


Apparently the reason the python weakref is testable is that you can
explicitly delete an object. At least that's what the test code seems
to do. This is not possible in ruby, and the ruby gc is not
deterministic enough to always free all unused objects. So it's not
the weakref what would need changing to make weakref testable but the
memory allocation (and especially deallocation) interface.

Thanks

Michal

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Taking a stab at getline Noob C Programming 40 03-04-2013 09:09 AM
LINQ and Entity Framework - Worth a stab? Cirene ASP .Net 6 09-08-2008 01:42 PM
Need camera advice sd memory, aa bat. image stab Bob Digital Photography 3 09-15-2006 08:16 PM
test test test test test test test Computer Support 2 07-02-2003 06:02 PM



Advertisments