""" Test refcounting and behavior of SCXX.
"""
from __future__ import absolute_import, print_function

import sys

from numpy.testing import TestCase, dec, assert_equal, assert_, assert_raises

from scipy.weave import inline_tools


class TestObjectConstruct(TestCase):
    #------------------------------------------------------------------------
    # Check that construction from basic types is allowed and have correct
    # reference counts
    #------------------------------------------------------------------------

    @dec.slow
    def test_int(self):
        # strange int value used to try and make sure refcount is 2.
        code = """
               py::object val = 1001;
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,1001)

    @dec.slow
    def test_float(self):
        code = """
               py::object val = (float)1.0;
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,1.0)

    @dec.slow
    def test_double(self):
        code = """
               py::object val = 1.0;
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,1.0)

    @dec.slow
    def test_complex(self):
        code = """
               std::complex<double> num = std::complex<double>(1.0,1.0);
               py::object val = num;
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,1.0+1.0j)

    @dec.slow
    def test_string(self):
        code = """
               py::object val = "hello";
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,"hello")

    @dec.slow
    def test_std_string(self):
        code = """
               std::string s = std::string("hello");
               py::object val = s;
               return_val = val;
               """
        res = inline_tools.inline(code)
        assert_equal(sys.getrefcount(res),2)
        assert_equal(res,"hello")

class TestObjectPrint(TestCase):
    #------------------------------------------------------------------------
    # Check the object print protocol.
    #------------------------------------------------------------------------

    @dec.slow
    def test_stringio(self):
        import cStringIO
        file_imposter = cStringIO.StringIO()
        code = """
               py::object val = "how now brown cow";
               val.print(file_imposter);
               """
        res = inline_tools.inline(code,['file_imposter'])
        print(file_imposter.getvalue())
        assert_equal(file_imposter.getvalue(),"'how now brown cow'")

##    @dec.slow
##    def test_failure(self):
##        code = """
##               FILE* file = 0;
##               py::object val = "how now brown cow";
##               val.print(file);
##               """
##        try:
##            res = inline_tools.inline(code)
##        except:
##            # error was supposed to occur.
##            pass


class TestObjectCast(TestCase):

    @dec.slow
    def test_int_cast(self):
        code = """
               py::object val = 1;
               int raw_val __attribute__ ((unused)) = val;
               """
        inline_tools.inline(code)

    @dec.slow
    def test_double_cast(self):
        code = """
               py::object val = 1.0;
               double raw_val __attribute__ ((unused)) = val;
               """
        inline_tools.inline(code)

    @dec.slow
    def test_float_cast(self):
        code = """
               py::object val = 1.0;
               float raw_val __attribute__ ((unused)) = val;
               """
        inline_tools.inline(code)

    @dec.slow
    def test_complex_cast(self):
        code = """
               std::complex<double> num = std::complex<double>(1.0, 1.0);
               py::object val = num;
               std::complex<double> raw_val __attribute__ ((unused)) = val;
               """
        inline_tools.inline(code)

    @dec.slow
    def test_string_cast(self):
        code = """
               py::object val = "hello";
               std::string raw_val __attribute__ ((unused)) = val;
               """
        inline_tools.inline(code)


# test class used for testing python class access from C++.
class Foo:
    def bar(self):
        return "bar results"
    def bar2(self,val1,val2):
        return val1, val2
    def bar3(self,val1,val2,val3=1):
        return val1, val2, val3

#class StrObj:
#    def __str__(self):
#        return "b"


class TestObjectHasattr(TestCase):

    @dec.slow
    def test_string(self):
        a = Foo()
        a.b = 12345
        code = """
               return_val = a.hasattr("b");
               """
        res = inline_tools.inline(code,['a'])
        assert_(res)

    @dec.slow
    def test_std_string(self):
        a = Foo()
        a.b = 12345
        attr_name = "b"
        code = """
               return_val = a.hasattr(attr_name);
               """
        res = inline_tools.inline(code,['a','attr_name'])
        assert_(res)

    @dec.slow
    def test_string_fail(self):
        a = Foo()
        a.b = 12345
        code = """
               return_val = a.hasattr("c");
               """
        res = inline_tools.inline(code,['a'])
        assert_(not res)

    @dec.slow
    def test_inline(self):
        """ THIS NEEDS TO MOVE TO THE INLINE TEST SUITE
        """
        a = Foo()
        a.b = 12345
        code = """
               throw_error(PyExc_AttributeError,"bummer");
               """
        try:
            before = sys.getrefcount(a)
            res = inline_tools.inline(code,['a'])
        except AttributeError:
            after = sys.getrefcount(a)
            try:
                res = inline_tools.inline(code,['a'])
            except:
                after2 = sys.getrefcount(a)
            print("after and after2 should be equal in the following")
            print('before, after, after2:', before, after, after2)
            pass

    @dec.slow
    def test_func(self):
        a = Foo()
        a.b = 12345
        code = """
               return_val = a.hasattr("bar");
               """
        res = inline_tools.inline(code,['a'])
        assert_(res)


class TestObjectAttr(TestCase):

    def generic_attr(self,code,args=['a']):
        a = Foo()
        a.b = 12345

        before = sys.getrefcount(a.b)
        res = inline_tools.inline(code,args)
        assert_equal(res,a.b)
        del res
        after = sys.getrefcount(a.b)
        assert_equal(after,before)

    @dec.slow
    def test_char(self):
        self.generic_attr('return_val = a.attr("b");')

    @dec.slow
    def test_char_fail(self):
        assert_raises(AttributeError, self.generic_attr, 'return_val = a.attr("c");')

    @dec.slow
    def test_string(self):
        self.generic_attr('return_val = a.attr(std::string("b"));')

    @dec.slow
    def test_string_fail(self):
        assert_raises(AttributeError, self.generic_attr, 'return_val = a.attr(std::string("c"));')

    @dec.slow
    def test_obj(self):
        code = """
               py::object name = "b";
               return_val = a.attr(name);
               """
        self.generic_attr(code,['a'])

    @dec.slow
    def test_obj_fail(self):
        code = """
               py::object name = "c";
               return_val = a.attr(name);
               """
        assert_raises(AttributeError, self.generic_attr, code, ['a'])

    @dec.slow
    def test_attr_call(self):
        a = Foo()
        res = inline_tools.inline('return_val = a.attr("bar").call();',['a'])
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.attr("bar").call();',['a'])
        second = sys.getrefcount(res)
        assert_equal(res,"bar results")
        assert_equal(first,second)


class TestObjectSetAttr(TestCase):

    def generic_existing(self, code, desired):
        args = ['a']
        a = Foo()
        a.b = 12345
        res = inline_tools.inline(code,args)
        assert_equal(a.b,desired)

    def generic_new(self, code, desired):
        args = ['a']
        a = Foo()
        res = inline_tools.inline(code,args)
        assert_equal(a.b,desired)

    @dec.slow
    def test_existing_char(self):
        self.generic_existing('a.set_attr("b","hello");',"hello")

    @dec.slow
    def test_new_char(self):
        self.generic_new('a.set_attr("b","hello");',"hello")

    @dec.slow
    def test_existing_string(self):
        self.generic_existing('a.set_attr("b",std::string("hello"));',"hello")

    @dec.slow
    def test_new_string(self):
        self.generic_new('a.set_attr("b",std::string("hello"));',"hello")

    @dec.slow
    def test_existing_object(self):
        code = """
               py::object obj = "hello";
               a.set_attr("b",obj);
               """
        self.generic_existing(code,"hello")

    @dec.slow
    def test_new_object(self):
        code = """
               py::object obj = "hello";
               a.set_attr("b",obj);
               """
        self.generic_new(code,"hello")

    @dec.slow
    def test_new_fail(self):
        try:
            code = """
                   py::object obj = 1;
                   a.set_attr(obj,"hello");
                   """
            self.generic_new(code,"hello")
        except:
            pass

    @dec.slow
    def test_existing_int(self):
        self.generic_existing('a.set_attr("b",1);',1)

    @dec.slow
    def test_existing_double(self):
        self.generic_existing('a.set_attr("b",1.0);',1.0)

    @dec.slow
    def test_existing_complex(self):
        code = """
               std::complex<double> obj = std::complex<double>(1,1);
               a.set_attr("b",obj);
               """
        self.generic_existing(code,1+1j)

    @dec.slow
    def test_existing_char1(self):
        self.generic_existing('a.set_attr("b","hello");',"hello")

    @dec.slow
    def test_existing_string1(self):
        code = """
               std::string obj = std::string("hello");
               a.set_attr("b",obj);
               """
        self.generic_existing(code,"hello")


class TestObjectDel(TestCase):

    def generic(self, code):
        args = ['a']
        a = Foo()
        a.b = 12345
        res = inline_tools.inline(code,args)
        assert_(not hasattr(a,"b"))

    @dec.slow
    def test_char(self):
        self.generic('a.del("b");')

    @dec.slow
    def test_string(self):
        code = """
               std::string name = std::string("b");
               a.del(name);
               """
        self.generic(code)

    @dec.slow
    def test_object(self):
        code = """
               py::object name = py::object("b");
               a.del(name);
               """
        self.generic(code)


class TestObjectCmp(TestCase):

    @dec.slow
    def test_equal(self):
        a,b = 1,1
        res = inline_tools.inline('return_val = (a == b);',['a','b'])
        assert_equal(res,(a == b))

    @dec.slow
    def test_equal_objects(self):
        class Foo:
            def __init__(self,x):
                self.x = x
            def __cmp__(self,other):
                return cmp(self.x,other.x)
        a,b = Foo(1),Foo(2)
        res = inline_tools.inline('return_val = (a == b);',['a','b'])
        assert_equal(res,(a == b))

    @dec.slow
    def test_lt(self):
        a,b = 1,2
        res = inline_tools.inline('return_val = (a < b);',['a','b'])
        assert_equal(res,(a < b))

    @dec.slow
    def test_gt(self):
        a,b = 1,2
        res = inline_tools.inline('return_val = (a > b);',['a','b'])
        assert_equal(res,(a > b))

    @dec.slow
    def test_gte(self):
        a,b = 1,2
        res = inline_tools.inline('return_val = (a >= b);',['a','b'])
        assert_equal(res,(a >= b))

    @dec.slow
    def test_lte(self):
        a,b = 1,2
        res = inline_tools.inline('return_val = (a <= b);',['a','b'])
        assert_equal(res,(a <= b))

    @dec.slow
    def test_not_equal(self):
        a,b = 1,2
        res = inline_tools.inline('return_val = (a != b);',['a','b'])
        assert_equal(res,(a != b))

    @dec.slow
    def test_int(self):
        a = 1
        res = inline_tools.inline('return_val = (a == 1);',['a'])
        assert_equal(res,(a == 1))

    @dec.slow
    def test_int2(self):
        a = 1
        res = inline_tools.inline('return_val = (1 == a);',['a'])
        assert_equal(res,(a == 1))

    @dec.slow
    def test_unsigned_long(self):
        a = 1
        res = inline_tools.inline('return_val = (a == (unsigned long)1);',['a'])
        assert_equal(res,(a == 1))

    @dec.slow
    def test_double(self):
        a = 1
        res = inline_tools.inline('return_val = (a == 1.0);',['a'])
        assert_equal(res,(a == 1.0))

    @dec.slow
    def test_char(self):
        a = "hello"
        res = inline_tools.inline('return_val = (a == "hello");',['a'])
        assert_equal(res,(a == "hello"))

    @dec.slow
    def test_std_string(self):
        a = "hello"
        code = """
               std::string hello = std::string("hello");
               return_val = (a == hello);
               """
        res = inline_tools.inline(code,['a'])
        assert_equal(res,(a == "hello"))


class TestObjectRepr(TestCase):

    @dec.slow
    def test_repr(self):
        class Foo:
            def __str__(self):
                return "str return"
            def __repr__(self):
                return "repr return"
        a = Foo()
        res = inline_tools.inline('return_val = a.repr();',['a'])
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.repr();',['a'])
        second = sys.getrefcount(res)
        assert_equal(first,second)
        assert_equal(res,"repr return")


class TestObjectStr(TestCase):

    @dec.slow
    def test_str(self):
        class Foo:
            def __str__(self):
                return "str return"
            def __repr__(self):
                return "repr return"
        a = Foo()
        res = inline_tools.inline('return_val = a.str();',['a'])
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.str();',['a'])
        second = sys.getrefcount(res)
        assert_equal(first,second)
        print(res)
        assert_equal(res,"str return")


class TestObjectUnicode(TestCase):

    # This ain't going to win awards for test of the year...

    @dec.slow
    def test_unicode(self):
        class Foo:
            def __repr__(self):
                return "repr return"
            def __str__(self):
                return "unicode"
        a= Foo()
        res = inline_tools.inline('return_val = a.unicode();',['a'])
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.unicode();',['a'])
        second = sys.getrefcount(res)
        assert_equal(first,second)
        assert_equal(res,"unicode")


class TestObjectIsCallable(TestCase):

    @dec.slow
    def test_true(self):
        class Foo:
            def __call__(self):
                return 0
        a= Foo()
        res = inline_tools.inline('return_val = a.is_callable();',['a'])
        assert_(res)

    @dec.slow
    def test_false(self):
        class Foo:
            pass
        a= Foo()
        res = inline_tools.inline('return_val = a.is_callable();',['a'])
        assert_(not res)


class TestObjectCall(TestCase):

    @dec.slow
    def test_noargs(self):
        def Foo():
            return (1,2,3)
        res = inline_tools.inline('return_val = Foo.call();',['Foo'])
        assert_equal(res,(1,2,3))
        assert_equal(sys.getrefcount(res),3) # should be 2?

    @dec.slow
    def test_args(self):
        def Foo(val1,val2):
            return (val1,val2)
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               return_val = Foo.call(args);
               """
        res = inline_tools.inline(code,['Foo'])
        assert_equal(res,(1,"hello"))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_args_kw(self):
        def Foo(val1,val2,val3=1):
            return (val1,val2,val3)
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               py::dict kw;
               kw["val3"] = 3;
               return_val = Foo.call(args,kw);
               """
        res = inline_tools.inline(code,['Foo'])
        assert_equal(res,(1,"hello",3))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_noargs_with_args(self):
        # calling a function that does take args with args
        # should fail.
        def Foo():
            return "blah"
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               return_val = Foo.call(args);
               """
        try:
            first = sys.getrefcount(Foo)
            res = inline_tools.inline(code,['Foo'])
        except TypeError:
            second = sys.getrefcount(Foo)
            try:
                res = inline_tools.inline(code,['Foo'])
            except TypeError:
                third = sys.getrefcount(Foo)
        # first should == second, but the weird refcount error
        assert_equal(second,third)


class TestObjectMcall(TestCase):

    @dec.slow
    def test_noargs(self):
        a = Foo()
        res = inline_tools.inline('return_val = a.mcall("bar");',['a'])
        assert_equal(res,"bar results")
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.mcall("bar");',['a'])
        assert_equal(res,"bar results")
        second = sys.getrefcount(res)
        assert_equal(first,second)

    @dec.slow
    def test_args(self):
        a = Foo()
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               return_val = a.mcall("bar2",args);
               """
        res = inline_tools.inline(code,['a'])
        assert_equal(res,(1,"hello"))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_args_kw(self):
        a = Foo()
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               py::dict kw;
               kw["val3"] = 3;
               return_val = a.mcall("bar3",args,kw);
               """
        res = inline_tools.inline(code,['a'])
        assert_equal(res,(1,"hello",3))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_std_noargs(self):
        a = Foo()
        method = "bar"
        res = inline_tools.inline('return_val = a.mcall(method);',['a','method'])
        assert_equal(res,"bar results")
        first = sys.getrefcount(res)
        del res
        res = inline_tools.inline('return_val = a.mcall(method);',['a','method'])
        assert_equal(res,"bar results")
        second = sys.getrefcount(res)
        assert_equal(first,second)

    @dec.slow
    def test_std_args(self):
        a = Foo()
        method = "bar2"
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               return_val = a.mcall(method,args);
               """
        res = inline_tools.inline(code,['a','method'])
        assert_equal(res,(1,"hello"))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_std_args_kw(self):
        a = Foo()
        method = "bar3"
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               py::dict kw;
               kw["val3"] = 3;
               return_val = a.mcall(method,args,kw);
               """
        res = inline_tools.inline(code,['a','method'])
        assert_equal(res,(1,"hello",3))
        assert_equal(sys.getrefcount(res),2)

    @dec.slow
    def test_noargs_with_args(self):
        # calling a function that does take args with args
        # should fail.
        a = Foo()
        code = """
               py::tuple args(2);
               args[0] = 1;
               args[1] = "hello";
               return_val = a.mcall("bar",args);
               """
        try:
            first = sys.getrefcount(a)
            res = inline_tools.inline(code,['a'])
        except TypeError:
            second = sys.getrefcount(a)
            try:
                res = inline_tools.inline(code,['a'])
            except TypeError:
                third = sys.getrefcount(a)
        # first should == second, but the weird refcount error
        assert_equal(second,third)


class TestObjectHash(TestCase):

    @dec.slow
    def test_hash(self):
        class Foo:
            def __hash__(self):
                return 123
        a= Foo()
        res = inline_tools.inline('return_val = a.hash(); ',['a'])
        print('hash:', res)
        assert_equal(res,123)


class TestObjectIsTrue(TestCase):

    @dec.slow
    def test_true(self):
        class Foo:
            pass
        a= Foo()
        res = inline_tools.inline('return_val = a.is_true();',['a'])
        assert_equal(res,1)

    @dec.slow
    def test_false(self):
        a= None
        res = inline_tools.inline('return_val = a.is_true();',['a'])
        assert_equal(res,0)


class TestObjectType(TestCase):

    @dec.slow
    def test_type(self):
        class Foo:
            pass
        a= Foo()
        res = inline_tools.inline('return_val = a.type();',['a'])
        assert_equal(res,type(a))


class TestObjectSize(TestCase):

    @dec.slow
    def test_size(self):
        class Foo:
            def __len__(self):
                return 10
        a= Foo()
        res = inline_tools.inline('return_val = a.size();',['a'])
        assert_equal(res,len(a))

    @dec.slow
    def test_len(self):
        class Foo:
            def __len__(self):
                return 10
        a= Foo()
        res = inline_tools.inline('return_val = a.len();',['a'])
        assert_equal(res,len(a))

    @dec.slow
    def test_length(self):
        class Foo:
            def __len__(self):
                return 10
        a= Foo()
        res = inline_tools.inline('return_val = a.length();',['a'])
        assert_equal(res,len(a))


from UserList import UserList


class TestObjectSetItemOpIndex(TestCase):

    @dec.slow
    def test_list_refcount(self):
        a = UserList([1,2,3])
        # temporary refcount fix until I understand why it incs by one.
        inline_tools.inline("a[1] = 1234;",['a'])
        before1 = sys.getrefcount(a)
        after1 = sys.getrefcount(a)
        assert_equal(after1,before1)

    @dec.slow
    def test_set_int(self):
        a = UserList([1,2,3])
        inline_tools.inline("a[1] = 1234;",['a'])
        assert_equal(sys.getrefcount(a[1]),2)
        assert_equal(a[1],1234)

    @dec.slow
    def test_set_double(self):
        a = UserList([1,2,3])
        inline_tools.inline("a[1] = 123.0;",['a'])
        assert_equal(sys.getrefcount(a[1]),2)
        assert_equal(a[1],123.0)

    @dec.slow
    def test_set_char(self):
        a = UserList([1,2,3])
        inline_tools.inline('a[1] = "bubba";',['a'])
        assert_equal(sys.getrefcount(a[1]),2)
        assert_equal(a[1],'bubba')

    @dec.slow
    def test_set_string1(self):
        a = UserList([1,2,3])
        inline_tools.inline('a[1] = std::string("sissy");',['a'])
        assert_equal(sys.getrefcount(a[1]),2)
        assert_equal(a[1],'sissy')

    @dec.slow
    def test_set_string2(self):
        a = UserList([1,2,3])
        inline_tools.inline('a[1] = std::complex<double>(1,1);',['a'])
        assert_equal(sys.getrefcount(a[1]),2)
        assert_equal(a[1],1+1j)


from UserDict import UserDict


class TestObjectSetItemOpKey(TestCase):

    @dec.slow
    def test_key_refcount(self):
        a = UserDict()
        code =  """
                py::object one = 1;
                py::object two = 2;
                py::tuple ref_counts(3);
                py::tuple obj_counts(3);
                py::tuple val_counts(3);
                py::tuple key_counts(3);
                obj_counts[0] = a.refcount();
                key_counts[0] = one.refcount();
                val_counts[0] = two.refcount();
                a[1] = 2;
                obj_counts[1] = a.refcount();
                key_counts[1] = one.refcount();
                val_counts[1] = two.refcount();
                a[1] = 2;
                obj_counts[2] = a.refcount();
                key_counts[2] = one.refcount();
                val_counts[2] = two.refcount();

                ref_counts[0] = obj_counts;
                ref_counts[1] = key_counts;
                ref_counts[2] = val_counts;
                return_val = ref_counts;
                """
        obj,key,val = inline_tools.inline(code,['a'])
        assert_equal(obj[0],obj[1])
        assert_equal(obj[1],obj[2])
        assert_equal(key[0] + 1, key[1])
        assert_equal(key[1], key[2])
        assert_equal(val[0] + 1, val[1])
        assert_equal(val[1], val[2])

    @dec.slow
    def test_set_double_exists(self):
        a = UserDict()
        key = 10.0
        a[key] = 100.0
        inline_tools.inline('a[key] = 123.0;',['a','key'])
        first = sys.getrefcount(key)
        inline_tools.inline('a[key] = 123.0;',['a','key'])
        second = sys.getrefcount(key)
        assert_equal(first,second)
        # !! I think the following should be 3
        assert_equal(sys.getrefcount(key),5)
        assert_equal(sys.getrefcount(a[key]),2)
        assert_equal(a[key],123.0)

    @dec.slow
    def test_set_double_new(self):
        a = UserDict()
        key = 1.0
        inline_tools.inline('a[key] = 123.0;',['a','key'])
        assert_equal(sys.getrefcount(key),4) # should be 3
        assert_equal(sys.getrefcount(a[key]),2)
        assert_equal(a[key],123.0)

    @dec.slow
    def test_set_complex(self):
        a = UserDict()
        key = 1+1j
        inline_tools.inline("a[key] = 1234;",['a','key'])
        assert_equal(sys.getrefcount(key),4) # should be 3
        assert_equal(sys.getrefcount(a[key]),2)
        assert_equal(a[key],1234)

    @dec.slow
    def test_set_char(self):
        a = UserDict()
        inline_tools.inline('a["hello"] = 123.0;',['a'])
        assert_equal(sys.getrefcount(a["hello"]),2)
        assert_equal(a["hello"],123.0)

    @dec.slow
    def test_set_class(self):
        a = UserDict()
        class Foo:
            def __init__(self,val):
                self.val = val
            def __hash__(self):
                return self.val
        key = Foo(4)
        inline_tools.inline('a[key] = "bubba";',['a','key'])
        first = sys.getrefcount(key)
        inline_tools.inline('a[key] = "bubba";',['a','key'])
        second = sys.getrefcount(key)
        # I don't think we're leaking if this is true
        assert_equal(first,second)
        # !! BUT -- I think this should be 3
        assert_equal(sys.getrefcount(key),4)
        assert_equal(sys.getrefcount(a[key]),2)
        assert_equal(a[key],'bubba')

    @dec.slow
    def test_set_from_member(self):
        a = UserDict()
        a['first'] = 1
        a['second'] = 2
        inline_tools.inline('a["first"] = a["second"];',['a'])
        assert_equal(a['first'],a['second'])


if __name__ == "__main__":
    import nose
    nose.run(argv=['', __file__])
