def setUp(self):
     self.s = SimDetectorDriver("S", "PRE")
     self.s.loop_run()
     self.in_params = dict(numImages=2, exposure=0.1)
     self.valid_params = {'abortTimeout': 1,
                          'arrayCounter': 0,
                          'configureTimeout': 1,
                          'exposure': 0.1,
                          'numImages': 2,
                          'period': 0.1,
                          'resetTimeout': 1,
                          'runTime': 0.2,
                          'runTimeout': 3*0.1}
     self.send_params = {'imageMode': "Multiple", 'exposure':
                         0.1, 'arrayCounter': 0, 'arrayCallbacks': 1,
                         'period': 0.1, 'numImages': 2}
class SimDetectorTest(unittest.TestCase):

    @patch("malcolm.devices.simdetectordriver.PvAttribute", DummyPVAttribute)
    def setUp(self):
        self.s = SimDetectorDriver("S", "PRE")
        self.s.loop_run()
        self.in_params = dict(numImages=2, exposure=0.1)
        self.valid_params = {'abortTimeout': 1,
                             'arrayCounter': 0,
                             'configureTimeout': 1,
                             'exposure': 0.1,
                             'numImages': 2,
                             'period': 0.1,
                             'resetTimeout': 1,
                             'runTime': 0.2,
                             'runTimeout': 3*0.1}
        self.send_params = {'imageMode': "Multiple", 'exposure':
                            0.1, 'arrayCounter': 0, 'arrayCallbacks': 1,
                            'period': 0.1, 'numImages': 2}

    def test_init(self):
        base = ['prefix', 'uptime']
        pvs = ['acquire', 'arrayCallbacks', 'arrayCounter', 'exposure',
               'imageMode', 'numImages', 'period', 'portName']
        self.assertEqual(self.s.attributes.keys(), base + pvs)
        self.assertEqual(self.s.prefix, "PRE")
        for attr in pvs:
            self.assertEqual(self.s.attributes[attr].value, None)
            self.assertEqual(self.s.attributes[attr].pv.call_args, None)

    def test_validate(self):
        actual = self.s.validate(**self.in_params)
        self.assertEqual(actual, self.valid_params)

    def set_configured(self):
        # Set all the pvs to the right value
        for attr in sorted(self.send_params):
            self.s.attributes[attr]._value = self.send_params[attr]
        self.s.configure(**self.in_params)
        self.assertEqual(self.s.state, DState.Ready)

    def test_mismatch(self):
        self.set_configured()
        Attribute.update(self.s.attributes["arrayCallbacks"], False)
        self.assertEqual(self.s.state, DState.Ready)
        cothread.Yield()
        self.assertEqual(self.s.state, DState.Idle)

    def check_set(self, attr, expected):
        self.assertEqual(self.s.attributes[attr].pv.caput.call_count, 1)
        call_args = self.s.attributes[attr].pv.caput.call_args
        val = call_args[0][0]
        self.assertEquals(
            val, expected, "{}: expected {} got {}".format(attr, expected, val))
        Attribute.update(self.s.attributes[attr], val)
        self.s.attributes[attr].pv.reset_mock()

    def test_configure(self):
        spawned = cothread.Spawn(self.s.configure, **self.in_params)
        # Yield to let configure run
        cothread.Yield()
        self.assertEqual(self.s.state, DState.Idle)
        # Yield to let do_config run
        cothread.Yield()
        self.assertEqual(self.s.state, DState.Configuring)
        for attr in sorted(self.send_params):
            self.check_set(attr, self.send_params[attr])
        spawned.Wait(1)
        self.assertEqual(self.s.stateMachine.state, DState.Ready)

    def test_run(self):
        self.set_configured()
        spawned = cothread.Spawn(self.s.run)
        # Yield to let run run
        cothread.Yield()
        self.assertEqual(self.s.state, DState.Ready)
        # Yield to let do_run run
        cothread.Yield()
        self.assertEqual(self.s.state, DState.Running)
        self.check_set("acquire", 1)
        self.assertEqual(self.s.acquire, 1)
        Attribute.update(self.s.attributes["acquire"], False)
        cothread.Yield()
        self.assertEqual(self.s.stateMachine.state, DState.Idle)
        spawned.Wait(1)
        self.assertEqual(self.s.stateMachine.state, DState.Idle)

    def test_abort(self):
        self.set_configured()
        spawned = cothread.Spawn(self.s.run)
        cothread.Yield()
        cothread.Yield()
        self.assertEqual(self.s.stateMachine.state, DState.Running)
        self.check_set("acquire", 1)
        self.assertEqual(self.s.acquire, 1)
        aspawned = cothread.Spawn(self.s.abort)
        cothread.Yield()
        cothread.Yield()
        self.assertEqual(self.s.stateMachine.state, DState.Aborting)
        self.check_set("acquire", 0)
        Attribute.update(self.s.attributes["acquire"], False)
        cothread.Yield()
        self.assertEqual(self.s.stateMachine.state, DState.Aborted)
        spawned.Wait(1)
        aspawned.Wait(1)