class TestLazyComponent(unittest.TestCase):
    
    def setUp(self): 
        self.top = Assembly()
        self.top.add("t", TestComp())
        self.top.add("s", SinkComp())
        self.top.driver.workflow.add(["t", "s"])
        self.top.set('t.a', 1)

    def tearDown(self): 
        self.top = None

    def test_full_connected(self): 
        self.top.connect('t.x', 's.i1')
        self.top.connect('t.y', 's.i2')
        self.top.connect('t.z', 's.i3')

        self.top.run()

        self.assertEqual(self.top.t.x, 2)
        self.assertEqual(self.top.t.y, 3)
        self.assertEqual(self.top.t.z, 4)

        self.assertEqual(self.top.get_valid(['t.x','t.y','t.z']),
                         [True,True,True])

    def test_partial_connected(self): 
        self.top.connect('t.x', 's.i1')
        self.top.connect('t.y', 's.i2')

        self.top.run()

        self.assertEqual(self.top.t.x, 2)
        self.assertEqual(self.top.t.y, 3)
        self.assertEqual(self.top.t.z, 0)

        self.assertEqual(self.top.get_valid(['t.x','t.y','t.z']),
                         [True,True,False])

        #now try re-running with a different configuration to test the validy reseting
        self.top.disconnect('t')
        self.top.connect('t.x', 's.i1')
        self.top.set('t.a', 2)

        self.top.run()

        self.assertEqual(self.top.t.x, 3)
        self.assertEqual(self.top.t.y, 3) #this value is carried over from the first run call, but it's wrong... so not valid
        self.assertEqual(self.top.t.z, 0)

        self.assertEqual(self.top.get_valid(['t.x','t.y','t.z']),
                         [True,False,False])

    #not needed right now, since we're not checking for this 
    #on regular component. 
    """def test_partial_connect_exec_error(self):
        self.top.add('t', BrokenTestComp())
        self.top.connect('t.x', 's.i1')
        self.top.set('t.a', 1)

        self.top.run()

        self.assertEqual(self.top.t.x, 10)
        self.assertEqual(self.top.t.y, 0)
        self.assertEqual(self.top.t.z, 0)

        self.top.connect('t.y', 's.i2')
        self.top.set('t.a', 2)

        try:
            self.top.run()
        except RuntimeError as err: 
            msg = str(err)
            self.assertEqual(msg, "t: output 'y' is connected to something in your model, but was not calculated during execution")
        else: 
            self.fail("RuntimeError Expected")
    """

    def test_new_connection_invalidation(self): 
        self.top.connect('t.x', 's.i1')
        self.top.set('t.a', 1)

        self.top.run()

        self.assertEqual(self.top.t.x, 2)
        self.assertEqual(self.top.t.y, 0)
        self.assertEqual(self.top.t.z, 0)

        self.assertEqual(self.top.get_valid(['t.x','t.y','t.z']),
                         [True,False,False])

        #new connection is made, but no inputs are invalid. Still need to run!
        self.top.connect('t.y', 's.i2')

        self.top.run()

        self.assertEqual(self.top.t.x, 2)
        self.assertEqual(self.top.t.y, 3)
        self.assertEqual(self.top.t.z, 0)

        self.assertEqual(self.top.get_valid(['t.x','t.y','t.z']),
                         [True,True,False])

    def test_dynamic_trait(self): 
        self.top.connect('t.x', 's.i1')
        self.top.connect('t.y', 's.i2')

        self.top.t.add('w', Float(0.0, iotype="out"))
        self.top.connect('t.w', 's.i3')

        #not checking for this yet
        #try:
        #    self.top.run()
        #except RuntimeError as err: 
        #    msg = str(err)
        #    self.assertEqual(msg, "t (1-1): output 'w' is connected to something in your model, but was not calculated during execution")
        #else: 
        #    self.fail("RuntimeError Expected")

        self.top.run()
        self.assertEqual(self.top.get_valid(['t.w','t.x','t.y','t.z']),
                         [True,True,True,False])

    def test_output_stays_at_default(self): 
        # check that validity is managed properly if outputs are calcualted, 
        # but their values stay at the initial/default setting

        #note: this is not really necessary, unless we start testing 
        #that outputs were actually calculated

        self.top.connect('t.x', 's.i1')
        self.top.set('t.a', -1)

        self.top.run()

        self.assertEqual(self.top.t.x, 0)
        self.assertEqual(self.top.t.y, 0)
        self.assertEqual(self.top.t.z, 0)

        self.assertEqual(self.top.t.get_valid(['x','y','z']),
                         [True,False,False])