"""
This module contains mix-in classes with methods designed to test RoachInterface instances.

These classes do not set up real or mock hardware, so they are not intended to be run directly. To use them, write a
class that inherits from one or more of them and has a setup() class method that creates a RoachInterface instance:
@classmethod
def setup(cls):
    cls.ri = set_up_roach_somehow()
using combination of real and mock hardware.

Currently, the setup() method is run before the tests in each mix-in class. I'm not sure how to get nose to stop doing
this, and in any case it's probably easier to write tests if each class can expects a fresh ROACH.
"""
import numpy as np

from kid_readout.measurement import core
from kid_readout.roach import calculate


class RoachMixin(object):
    """
    This class has methods that are tests applicable to all ROACH types and configurations.
    """

    def test_state(self):
        _ = self.ri.state
        _ = self.ri.get_state()
        _ = self.ri.state_arrays
        _ = self.ri.get_state_arrays()
        _ = self.ri.active_state_arrays
        _ = self.ri.get_active_state_arrays()

    def test_precomputed_wavenorm(self):
        np.random.seed(123)
        for k in range(9):
            self.ri.set_tone_baseband_freqs(np.linspace(100, 120, 2 ** k), nsamp=2 ** 16, preset_norm=False)
            actual_wavenorm = self.ri.wavenorm
            self.ri.set_tone_baseband_freqs(np.linspace(100, 120, 2 ** k), nsamp=2 ** 16, phases=self.ri.phases,
                                            preset_norm=True)
            assert self.ri.wavenorm >= 0.99 * actual_wavenorm  # guarantees the wave won't overflow

    def test_calculate_modulation_period(self):
        roach_state = core.StateDict(modulation_rate=7, modulation_output=2, heterodyne=True)
        assert calculate.modulation_period_samples(roach_state) == 256
        roach_state = core.StateDict(modulation_rate=7, modulation_output=2, heterodyne=False)
        assert calculate.modulation_period_samples(roach_state) == 128


    def test_get_measurement_blocks(self):
        num_tones = 32
        self.ri.set_tone_baseband_freqs(np.linspace(100, 120, num_tones), nsamp=2 ** 16)
        self.ri.select_fft_bins(range(num_tones))
        _ = self.ri.get_measurement_blocks(2)

    def test_get_current_bank(self):
        assert self.ri.get_current_bank() is not None

    def test_hardware_delay(self):
        if self.ri.heterodyne: