import py
import unittest
import sys
from py.__.test.collect import configproperty as _configproperty

unittest.failureException = AssertionError

def configproperty(name):
    def fget(self):
        ret = self._config.getvalue(name, self.fspath)
        return ret
    return property(fget)

class Module(py.test.collect.Module):
    UnitTestCase = configproperty('UnitTestCase')
    def makeitem(self, name, obj, usefilters=True):
        # XXX add test_suite() support(?)
        if py.std.inspect.isclass(obj) and issubclass(obj, unittest.TestCase):
            return self.UnitTestCase(name, parent=self)
        elif callable(obj) and getattr(obj, 'func_name', '') == 'test_suite':
            return None
        return super(Module, self).makeitem(name, obj, usefilters)

class UnitTestCase(py.test.collect.Class):
    TestCaseInstance = configproperty('TestCaseInstance')
    def join(self, name):
        assert name == '()'
        return self.TestCaseInstance(name, self)

    def setup(self):
        pass

    def teardown(self):
        pass

_dummy = object()
class TestCaseInstance(py.test.collect.Instance):
    UnitTestFunction = configproperty('UnitTestFunction')
    def run(self):
        loader = unittest.TestLoader()
        ret = loader.getTestCaseNames(self.obj.__class__)
        return ret

    def _getobj(self):
        return self.parent.obj(methodName='run')
        
    def makeitem(self, name, obj, usefilters=True):
        if callable(obj):
            return self.UnitTestFunction(name, parent=self)
        return super(TestCaseInstance, self).makeitem(name, obj, usefilters)

class UnitTestFunction(py.__.test.item.Function):
    def __init__(self, name, parent, args=(), obj=_dummy, sort_value=None):
        super(UnitTestFunction, self).__init__(name, parent)
        self._args = args
        if obj is not _dummy:
            self._obj = obj
        self._sort_value = sort_value

    def run(self):
        self.execute(self.obj, *self._args)

    def execute(self, target, *args):
        self.setup()
        try:
            target(*args)
        except:
            exc, e, tb = sys.exc_info()
            msg = str(e)
            del tb
            self.teardown()
            py.test.fail(msg)
        else:
            self.teardown()

    def setup(self):
        instance = self.obj.im_self
        instance.setUp()

    def teardown(self):
        instance = self.obj.im_self
        instance.tearDown()


