Commit d2570926 authored by Davide Ricci's avatar Davide Ricci
Browse files

removed tests

parent d444cbb3
Loading
Loading
Loading
Loading
Loading

temp.fits

deleted100644 → 0
−32.6 MiB

File deleted.

Preview size limit exceeded, changes collapsed.

tests/__init__.py

deleted100644 → 0
+0 −3
Original line number Diff line number Diff line
'''
Unit tests for the package
'''

tests/test_cameras.py

deleted100644 → 0
+0 −270
Original line number Diff line number Diff line
import os
import tempfile
import unittest
from unittest.mock import patch, MagicMock, ANY

from noctua import devices


def mock_resp(text):
    """Build a minimal mock requests.Response."""
    r = MagicMock()
    r.text = text if isinstance(text, str) else text.decode()
    r.content = text if isinstance(text, bytes) else text.encode()
    r.raise_for_status.return_value = None
    return r


# ─────────────────────────────────────────────────────────────
# STX Camera  (devices.cam)
# ─────────────────────────────────────────────────────────────

class TestSTXCamera(unittest.TestCase):
    """Unit tests for stx.Camera via devices.cam."""

    def setUp(self):
        devices.cam._command_interval = 0
        devices.cam.error = []

    @patch('noctua.devices.stx.requests.get')
    def test_abort(self, mock_get):
        mock_get.return_value = mock_resp("OK\r\n")
        devices.cam.abort()
        args, _ = mock_get.call_args
        self.assertIn("ImagerAbortExposure", args[0])

    @patch('noctua.devices.stx.requests.get')
    def test_start_when_idle(self, mock_get):
        mock_get.side_effect = [
            mock_resp("0\r\n"),   # state → 0.0 (idle)
            mock_resp("OK\r\n"),  # StartExposure
        ]
        devices.cam.start(10.0, 1)
        self.assertEqual(mock_get.call_count, 2)
        self.assertEqual(devices.cam.error, [])

    @patch('noctua.devices.stx.requests.get')
    def test_start_not_idle(self, mock_get):
        mock_get.return_value = mock_resp("2\r\n")  # state = 2 (exposing)
        devices.cam.start(10.0, 1)
        # state is queried twice: in `if self.state` and in the log message
        for call_args in mock_get.call_args_list:
            self.assertIn("ImagerState", call_args[0][0])
        self.assertIn("Camera not idle", devices.cam.error)

    @patch('noctua.devices.stx.requests.get')
    def test_start_passes_datetime(self, mock_get):
        mock_get.side_effect = [
            mock_resp("0\r\n"),
            mock_resp("OK\r\n"),
        ]
        devices.cam.start(5.0, 1, datetime="2024-06-01T00:00:00.000")
        _, kwargs = mock_get.call_args
        self.assertIn("DateTime", kwargs.get('params', ''))

    @patch('noctua.devices.stx.requests.get')
    def test_full_frame_returns_size(self, mock_get):
        mock_get.side_effect = [
            mock_resp("4096\r\n4126\r\n"),  # CameraXSize, CameraYSize
            mock_resp("0\r\n"),              # state in set_window
            mock_resp("OK\r\n"),             # SetSettings
        ]
        result = devices.cam.full_frame()
        self.assertEqual(result, [4096, 4126])

    @patch('noctua.devices.stx.requests.get')
    def test_half_frame_returns_size(self, mock_get):
        mock_get.side_effect = [
            mock_resp("4096\r\n4126\r\n"),
            mock_resp("0\r\n"),
            mock_resp("OK\r\n"),
        ]
        result = devices.cam.half_frame()
        self.assertEqual(result, [4096 // 2, 4126 // 2])

    @patch('noctua.devices.stx.requests.get')
    def test_small_frame_returns_size(self, mock_get):
        mock_get.side_effect = [
            mock_resp("4096\r\n4126\r\n"),
            mock_resp("0\r\n"),
            mock_resp("OK\r\n"),
        ]
        result = devices.cam.small_frame()
        self.assertEqual(result, [4096 // 10, 4126 // 10])

    @patch('noctua.devices.stx.requests.get')
    def test_state(self, mock_get):
        mock_get.return_value = mock_resp("0\r\n")
        self.assertEqual(devices.cam.state, 0.0)

    @patch('noctua.devices.stx.requests.get')
    def test_binning_get(self, mock_get):
        mock_get.return_value = mock_resp("2\r\n2\r\n")
        self.assertEqual(devices.cam.binning, [2, 2])

    @patch('noctua.devices.stx.requests.get')
    def test_binning_set(self, mock_get):
        mock_get.side_effect = [
            mock_resp("0\r\n"),
            mock_resp("OK\r\n"),
        ]
        devices.cam.binning = [2, 2]
        self.assertEqual(mock_get.call_count, 2)

    @patch('noctua.devices.stx.requests.get')
    def test_filter_get(self, mock_get):
        mock_get.return_value = mock_resp("3\r\n")
        self.assertEqual(devices.cam.filter, 3.0)

    @patch('noctua.devices.stx.requests.get')
    def test_filter_set(self, mock_get):
        mock_get.side_effect = [
            mock_resp("0\r\n"),   # is_moving check
            mock_resp("OK\r\n"),  # ChangeFilter
        ]
        devices.cam.filter = 2
        self.assertEqual(mock_get.call_count, 2)

    @patch('noctua.devices.stx.requests.get')
    def test_all_has_all_keys(self, mock_get):
        # 13 values matching ImagerGetSettings params order
        settings = (
            "20.5\r\n-10.0\r\n-5.3\r\n"
            "1\r\n45\r\n"
            "1\r\n1\r\n"
            "4096\r\n4126\r\n"
            "0\r\n0\r\n4096\r\n4126\r\n"
        )
        mock_get.side_effect = [
            mock_resp(settings),
            mock_resp("0\r\n"),
            mock_resp("STX-16803\r\n"),
        ]
        result = devices.cam.all
        expected_keys = {
            "ambient", "setpoint", "temperature", "cooler", "fan",
            "binning", "max_range", "xystart", "xyend",
            "xrange", "yrange", "center", "state", "description",
        }
        self.assertEqual(set(result.keys()), expected_keys)

    @patch('noctua.devices.stx.requests.get')
    def test_download_writes_file(self, mock_get):
        fake_content = b"SIMPLE  =                    T"
        mock_get.return_value = mock_resp(fake_content)
        with tempfile.TemporaryDirectory() as tmpdir:
            filepath = os.path.join(tmpdir, "test.fits")
            devices.cam.download(filepath=filepath)
            self.assertTrue(os.path.exists(filepath))
            with open(filepath, 'rb') as f:
                self.assertEqual(f.read(), fake_content)


# ─────────────────────────────────────────────────────────────
# Atik Camera  (devices.cam2)
# ─────────────────────────────────────────────────────────────

class TestAtikCamera(unittest.TestCase):
    """Unit tests for atik.Camera via devices.cam2."""

    def setUp(self):
        self.mock_lib = MagicMock()
        devices.cam2._lib = self.mock_lib
        devices.cam2._handle = MagicMock(name='fake_handle')  # truthy → skips _check_connection
        devices.cam2._props.nPixelsX = 4096
        devices.cam2._props.nPixelsY = 4126
        devices.cam2._subframe = [0, 0, 4096, 4126]
        devices.cam2.error = []

    def test_abort(self):
        devices.cam2.abort()
        self.mock_lib.ArtemisAbortExposure.assert_called_once_with(devices.cam2._handle)

    def test_start_light(self):
        devices.cam2.start(10.0, 1)
        self.mock_lib.ArtemisSetDarkMode.assert_called_once_with(devices.cam2._handle, False)
        self.mock_lib.ArtemisStartExposure.assert_called_once()

    def test_start_dark(self):
        devices.cam2.start(10.0, 0)
        self.mock_lib.ArtemisSetDarkMode.assert_called_once_with(devices.cam2._handle, True)

    def test_start_bias_is_dark(self):
        devices.cam2.start(0.0, 2)
        self.mock_lib.ArtemisSetDarkMode.assert_called_once_with(devices.cam2._handle, True)

    def test_start_accepts_datetime_kwarg(self):
        devices.cam2.start(5.0, 1, datetime="2024-06-01T00:00:00.000")
        self.mock_lib.ArtemisStartExposure.assert_called_once()

    def test_full_frame_returns_size(self):
        result = devices.cam2.full_frame()
        self.assertEqual(result, [4096, 4126])
        self.mock_lib.ArtemisSubframe.assert_called_once_with(
            devices.cam2._handle, 0, 0, 4096, 4126)
        self.assertEqual(devices.cam2._subframe, [0, 0, 4096, 4126])

    def test_half_frame_returns_size(self):
        result = devices.cam2.half_frame()
        self.assertEqual(result, [4096, 4126 // 2])
        self.mock_lib.ArtemisSubframe.assert_called_once_with(
            devices.cam2._handle, 0, 4126 // 4, 4096, 4126 // 2)
        self.assertEqual(devices.cam2._subframe, [0, 4126 // 4, 4096, 4126 // 2])

    def test_small_frame_returns_size(self):
        result = devices.cam2.small_frame()
        self.assertEqual(result, [4096, 500])
        self.mock_lib.ArtemisSubframe.assert_called_once_with(
            devices.cam2._handle, 0, 1500, 4096, 500)
        self.assertEqual(devices.cam2._subframe, [0, 1500, 4096, 500])

    def test_state(self):
        self.mock_lib.ArtemisCameraState.return_value = 0
        self.assertEqual(devices.cam2.state, 0)

    def test_binning_get_calls_sdk(self):
        result = devices.cam2.binning
        self.assertIsInstance(result, list)
        self.assertEqual(len(result), 2)
        self.mock_lib.ArtemisGetBin.assert_called_once_with(devices.cam2._handle, ANY, ANY)

    def test_binning_set(self):
        devices.cam2.binning = [2, 2]
        self.mock_lib.ArtemisBin.assert_called_once_with(devices.cam2._handle, 2, 2)

    def test_filter_get_returns_zero(self):
        self.assertEqual(devices.cam2.filter, 0)

    def test_filter_set_is_noop(self):
        devices.cam2.filter = 3
        self.assertEqual(self.mock_lib.method_calls, [])

    def test_all_has_all_keys(self):
        self.mock_lib.ArtemisCameraState.return_value = 0
        result = devices.cam2.all
        expected_keys = {
            "ambient", "setpoint", "temperature", "cooler", "fan",
            "binning", "max_range", "xystart", "xyend",
            "xrange", "yrange", "center", "state", "description",
        }
        self.assertEqual(set(result.keys()), expected_keys)

    def test_all_xystart_reflects_subframe(self):
        devices.cam2._subframe = [512, 256, 4096, 500]
        self.mock_lib.ArtemisCameraState.return_value = 0
        result = devices.cam2.all
        self.assertIn("xystart", result)
        self.assertIn("xyend", result)

    def test_download_polls_image_ready(self):
        self.mock_lib.ArtemisImageReady.return_value = 1
        self.mock_lib.ArtemisImageBuffer.return_value = 0  # null ptr → skip write
        with tempfile.TemporaryDirectory() as tmpdir:
            devices.cam2.download(filepath=os.path.join(tmpdir, "test.fits"))
        self.mock_lib.ArtemisImageReady.assert_called()
        self.mock_lib.ArtemisGetImageData.assert_called()
        self.mock_lib.ArtemisImageBuffer.assert_called()


if __name__ == '__main__':
    unittest.main()

tests/test_devices_access.py

deleted100644 → 0
+0 −159
Original line number Diff line number Diff line
      
# tests/test_device_access.py
import unittest
from unittest.mock import patch, MagicMock, mock_open
import configparser # To mock config loading

# We need to ensure 'noctua.devices' can be imported.
# If 'noctua' is not yet installed, and tests are run from project root:
# Make sure the project root is in PYTHONPATH or use `python -m unittest ...`

class TestDevicePropertyAccess(unittest.TestCase):

    @patch('noctua.devices.configparser.ConfigParser')
    @patch('noctua.devices.importlib.import_module') # Patch import_module used in devices/__init__.py
    def setUp(self, mock_import_module, mock_config_parser_constructor):
        """
        Set up mock configurations to allow 'noctua.devices' to "load"
        dummy devices without real hardware or full config files.
        """
        # Mock ConfigParser instances
        self.mock_nodes_config = MagicMock(spec=configparser.ConfigParser)
        self.mock_devs_config = MagicMock(spec=configparser.ConfigParser)

        # Configure the constructor to return our mocks
        mock_config_parser_constructor.side_effect = [
            self.mock_nodes_config,  # First call to ConfigParser() in devices/__init__
            self.mock_devs_config    # Second call
        ]

        # --- Mock nodes.ini content ---
        # Simulating [DUMMY_NODE] ip=localhost port=1234
        self.mock_nodes_config.items.return_value = [('ip', 'localhost'), ('port', '1234')]

        # --- Mock devices.ini content ---
        # Simulate one dome and one camera
        self.mock_devs_config.sections.return_value = ['dom', 'cam', 'tel']
        
        # Values for test_dom
        def devs_get_dom(section, option):
            if section == 'dom':
                if option == 'module': return 'alpaca' # Or whatever module 'dom' usually is
                if option == 'class': return 'Dome'
                if option == 'node': return 'DUMMY_NODE'
            raise configparser.NoOptionError(option, section)

        # Values for test_cam
        def devs_get_cam(section, option):
            if section == 'cam':
                if option == 'module': return 'stx' # Or your camera module
                if option == 'class': return 'Camera'
                if option == 'node': return 'DUMMY_NODE'
                if option == 'outlet': return '0' # if it's a switch-like camera power
            raise configparser.NoOptionError(option, section)

        # Values for test_cam
        def devs_get_tel(section, option):
            if section == 'tel':
                if option == 'module': return 'astelco' # Or your camera module
                if option == 'class': return 'Telescope'
                if option == 'node': return 'DUMMY_NODE'
            raise configparser.NoOptionError(option, section)

        # Side effect for devs.get based on section
        def devs_get_side_effect(section, option):
            if section == 'dom':
                return devs_get_dom(section, option)
            elif section == 'cam':
                return devs_get_cam(section, option)
            elif section == 'tel':
                return devs_get_tel(section, option)
            raise configparser.NoSectionError(section)

        self.mock_devs_config.get.side_effect = devs_get_side_effect

        # --- Mock the dynamically imported modules and classes ---
        self.mock_dome_module = MagicMock()
        self.mock_dome_class = MagicMock()
        self.mock_dome_instance = MagicMock(spec_set=['azimuth', 'error']) # spec_set for strictness
        self.mock_dome_instance.azimuth = 123.45
        self.mock_dome_instance.error = []
        self.mock_dome_class.return_value = self.mock_dome_instance
        self.mock_dome_module.Dome = self.mock_dome_class # Class name must match devices.ini

        self.mock_camera_module = MagicMock()
        self.mock_camera_class = MagicMock()
        self.mock_camera_instance = MagicMock(spec_set=['binning', 'error'])
        self.mock_camera_instance.binning = [1,1]
        self.mock_camera_instance.error = []
        self.mock_camera_class.return_value = self.mock_camera_instance
        self.mock_camera_module.Camera = self.mock_camera_class

        self.mock_telescope_module = MagicMock()
        self.mock_telescope_class = MagicMock()
        self.mock_telescope_instance = MagicMock(spec_set=['altaz', 'error'])
        self.mock_telescope_instance.altaz = [1,1]
        self.mock_telescope_instance.error = []
        self.mock_telescope_class.return_value = self.mock_telescope_instance
        self.mock_telescope_module.Telescope = self.mock_telescope_class

        def import_module_side_effect(name, package=None):
            # The name will be like 'noctua.devices.alpaca'
            if 'alpaca' in name: # Or your actual dome module name
                return self.mock_dome_module
            elif 'stx' in name: # Or your actual camera module name
                return self.mock_camera_module
            elif 'astelco' in name: # Or your actual telescope module name
                return self.mock_camera_module
            raise ImportError(f"Mocked import_module cannot find {name}")
        
        mock_import_module.side_effect = import_module_side_effect
        
        # Now, import noctua.devices. This will trigger its __init__.py
        # We need to ensure that if devices is already imported, it's reloaded with mocks.
        # This can be tricky. It's often better to ensure tests run in a clean environment
        # or explicitly reload. For simplicity, we assume it's the first import or
        # the mocks effectively override.
        
        # If 'noctua.devices' might already be loaded by another test:
        import sys
        if 'noctua.devices' in sys.modules:
            del sys.modules['noctua.devices'] # Force a reload
            if 'noctua.devices.alpaca' in sys.modules: del sys.modules['noctua.devices.alpaca']
            if 'noctua.devices.stx' in sys.modules: del sys.modules['noctua.devices.stx']
            if 'noctua.devices.astelco' in sys.modules: del sys.modules['noctua.devices.astelco']
            # Add other device modules if necessary

        from noctua import devices
        self.devices = devices


    def test_dome_azimuth_access(self):
        """Test accessing devices.dom.azimuth."""
        # devices.test_dom is our mock_dome_instance
        self.assertEqual(self.devices.dom.azimuth, 123.45)
        self.assertEqual(self.devices.dom.error, [])

    def test_telescope_altaz_access(self):
        """Test accessing devices.test_dom.altaz."""
        self.assertEqual(self.devices.tel.altaz, [45.0, 180.0])
        self.assertEqual(self.devices.tel.error, [])

    def test_camera_binning_access(self):
        """Test accessing devices.test_cam.binning."""
        self.assertEqual(self.devices.cam.binning, [1,1])
        self.assertEqual(self.devices.cam.error, [])

    def test_non_existent_device_attribute_error(self):
        """Test accessing a non-existent device raises AttributeError."""
        with self.assertRaises(AttributeError):
            _ = self.devices.non_existent_device

# Note: This setUp is quite involved because it mocks the dynamic
# loading.  An alternative for simpler unit tests is to *not* rely on
# `from noctua import devices` and instead directly instantiate and
# test the device classes (e.g., `alpaca.Dome`) by mocking their
# specific dependencies (e.g., `requests.get`).  The test above is
# more of an "integration unit test" for the devices package loading.

    

tests/test_devices_alpaca.py

deleted100644 → 0
+0 −30
Original line number Diff line number Diff line
import unittest
from unittest.mock import patch, MagicMock

# Assuming your project structure allows this import when tests are run
# from the project root (e.g., python -m unittest discover)
from noctua.devices import alpaca # Or directly import specific classes like Dome, Switch
from noctua.devices.__init__ import dynamic_import # To load devices based on config for integration-like unit tests

# You'll need a way to configure device instances for testing,
# or use the dynamic import mechanism if your test environment
# has access to dummy config files.

# For pure unit tests, directly instantiate:
# MOCK_URL = "http://mock-alpaca-server"
# test_switch = alpaca.Switch(MOCK_URL, switch_id=1, device_name="TestAlpacaSwitch")

class TestAlpacaSwitch(unittest.TestCase):
    def setUp(self):
        # This method is run before each test
        self.mock_url = "http://mock-alpaca-server.test"
        # device_name is added if you adopted the BaseDevice change. If not, remove it.
        self.switch = alpaca.Switch(self.mock_url, switch_id=0, device_name="TestAlpacaSwitch0")
        # Clear any errors from previous test runs if the instance is reused (not typical in setUp)
        if hasattr(self.switch, 'error'):
            self.switch.error = []

    # ... test methods ...

if __name__ == '__main__':
    unittest.main()
Loading