class AssemblerTest(unittest.TestCase):
    def setUp(self):
        self.assembler = Assembler()

    def test_instance(self):
        thing = object()
        self.assembler.instance('thing', thing)
        result = self.assembler.assemble('thing')
        self.assertEqual(thing, result)

    def test_factory(self):
        def thing_maker():
            return object()
        self.assembler.factory('thing', thing_maker)
        result1 = self.assembler.assemble('thing')
        self.assertTrue(isinstance(result1, object))
        result2 = self.assembler.assemble('thing')
        self.assertTrue(isinstance(result2, object))
        self.assertNotEqual(result1, result2)

    def test_assemble_with_args(self):
        def thing_maker(one, two):
            return [one, two]
        self.assembler.factory('thing', thing_maker)
        result = self.assembler.assemble('thing', 'one', 'two')
        self.assertEqual(['one', 'two'], result)

    def test_assemble_with_kwargs(self):
        def thing_maker(one, two):
            return [one, two]
        self.assembler.factory('thing', thing_maker)
        result = self.assembler.assemble('thing', two='one', one='two')
        self.assertEqual(['two', 'one'], result)

    def test_assemble_with_args_and_kwargs(self):
        def thing_maker(one, two, a=None, b=None):
            return [one, two, (a, b)]
        self.assembler.factory('thing', thing_maker)
        result = self.assembler.assemble('thing', 'one', 'two', b='b', a='a')
        self.assertEqual(['one', 'two', ('a', 'b')], result)

    def test_assemble_with_defaults(self):
        def thing_maker(one='one', two='two', a='a', b='b'):
            return [one, two, (a, b)]
        self.assembler.factory('thing', thing_maker)
        result = self.assembler.assemble('thing')
        self.assertEqual(['one', 'two', ('a', 'b')], result)

    def test_recursive_assemble(self):
        def thing1_maker(thing2):
            return thing2

        def thing2_maker():
            return 'instance of thing2'
        self.assembler.factory('thing1', thing1_maker)
        self.assembler.factory('thing2', thing2_maker)
        result = self.assembler.assemble('thing1')
        self.assertEqual('instance of thing2', result)

    def test_class_constructors(self):
        class A(object):
            def __init__(self, b, c):
                self.b = b
                self.c = c

        class B(object):
            def __init__(self):
                pass

        class C(object):
            def __init__(self, d):
                self.d = d

        class D(object):
            def __init__(self):
                pass
        self.assembler.factory('a', A)
        self.assembler.factory('b', B)
        self.assembler.factory('c', C)
        self.assembler.factory('d', D)
        a = self.assembler.assemble('a')
        self.assertTrue(isinstance(a, A))
        self.assertTrue(hasattr(a, 'b'))
        self.assertNotEqual(None, a.b)
        self.assertTrue(isinstance(a.b, B))
        self.assertTrue(hasattr(a, 'c'))
        self.assertNotEqual(None, a.c)
        self.assertTrue(isinstance(a.c, C))
        self.assertTrue(hasattr(a.c, 'd'))
        self.assertNotEqual(None, a.c.d)
        self.assertTrue(isinstance(a.c.d, D))