# Copyright (c) 2021-2025 The University of Texas Southwestern Medical Center. # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted for academic and research use only # (subject to the limitations in the disclaimer below) # provided that the following conditions are met: # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY # THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # Standard Imports import unittest import yaml import os # Third Party Imports # Local Imports class TestConfiguration(unittest.TestCase): def setUp(self): current_path = os.path.abspath(os.path.dirname(__file__)) root_path = os.path.dirname(os.path.dirname(current_path)) yaml_path = os.path.join( root_path, "src", "navigate", "config", "configuration.yaml" ) with open(yaml_path) as file: self.data = yaml.safe_load(file) def tearDown(self): pass # # hardware head section has been removed # def test_hardware_section(self): # expected_hardware = ["daq", "camera", "filter_wheel", "stage", "zoom"] # hardware_types = self.data["hardware"].keys() # for hardware_type in hardware_types: # self.assertIn(hardware_type, expected_hardware) # if isinstance(self.data["hardware"][hardware_type], dict): # hardware_keys = self.data["hardware"][hardware_type].keys() # for key in hardware_keys: # self.assertIn("type", self.data["hardware"][hardware_type]) # elif isinstance(self.data["hardware"][hardware_type], list): # for i in range(len(self.data["hardware"][hardware_type])): # self.assertIn("type", self.data["hardware"][hardware_type][i]) def test_gui_section(self): expected_keys = ["channels"] expected_channel_keys = [ "count", # "laser_power", # "exposure_time", # "interval_time", ] expected_stack_keys = ["step_size", "start_pos", "end_pos"] min_max_step_keys = ["min", "max", "step"] gui_keys = self.data["gui"].keys() for key in gui_keys: self.assertIn(key, expected_keys) # Channels Entry if key == "channels": channel_keys = self.data["gui"][key].keys() for channel_key in channel_keys: self.assertIn(channel_key, expected_channel_keys) if channel_key != "count": channel_key_keys = self.data["gui"][key][channel_key].keys() for channel_key_key in channel_key_keys: self.assertIn(channel_key_key, min_max_step_keys) # Stack Acquisition Entry elif key == "stack_acquisition": stack_keys = self.data["gui"][key].keys() for stack_key in stack_keys: self.assertIn(stack_key, expected_stack_keys) stack_key_keys = self.data["gui"][key][stack_key].keys() for stack_key_key in stack_key_keys: self.assertIn(stack_key_key, min_max_step_keys) # Timepoint Entry elif key == "timepoint": timepoint_keys = self.data["gui"][key].keys() for timepoint_key in timepoint_keys: timepoint_key_keys = self.data["gui"][key][timepoint_key].keys() for timepoint_key_key in timepoint_key_keys: self.assertIn(timepoint_key_key, min_max_step_keys) else: raise ValueError("Unexpected key in gui section") def test_microscope_section(self): expected_hardware = [ "daq", "camera", "remote_focus", "galvo", "shutter", "laser", "filter_wheel", "stage", "zoom", ] microscopes = self.data["microscopes"].keys() for microscope in microscopes: hardware = self.data["microscopes"][microscope].keys() for hardware_type in hardware: self.assertIn(hardware_type, expected_hardware) if hardware_type == "daq": self.daq_section(microscope=microscope, hardware_type=hardware_type) elif hardware_type == "camera": self.camera_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "remote_focus": self.remote_focus_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "galvo": self.galvo_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "filter_wheel": self.filter_wheel_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "stage": self.stage_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "zoom": self.zoom_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "shutter": self.shutter_section( microscope=microscope, hardware_type=hardware_type ) elif hardware_type == "laser": self.laser_section( microscope=microscope, hardware_type=hardware_type ) else: raise ValueError("Unexpected hardware type") def daq_section(self, microscope, hardware_type): expected_daq_keys = [ "hardware", "sample_rate", "sweep_time", "master_trigger_out_line", "camera_trigger_out_line", "trigger_source", "laser_port_switcher", "laser_switch_state", ] type_keys = ["type"] daq_keys = self.data["microscopes"][microscope][hardware_type].keys() for key in daq_keys: if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) else: self.assertIn(key, expected_daq_keys) def camera_section(self, microscope, hardware_type): expected_keys = [ "hardware", "defect_correct_mode", "delay", "settle_down", "flip_x", "flip_y", ] type_keys = ["type", "serial_number", "camera_connection"] camera_keys = self.data["microscopes"][microscope][hardware_type].keys() for key in camera_keys: if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) else: self.assertIn(key, expected_keys) def remote_focus_section(self, microscope, hardware_type): expected_keys = [ "hardware", ] type_keys = ["type", "channel", "min", "max", "port", "baudrate"] remote_focus_keys = self.data["microscopes"][microscope][hardware_type].keys() for key in remote_focus_keys: if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) else: self.assertIn(key, expected_keys) def galvo_section(self, microscope, hardware_type): expected_keys = [ "hardware", "waveform", "phase", ] type_keys = ["type", "channel", "min", "max"] if isinstance(self.data["microscopes"][microscope][hardware_type], list): for i in range(len(self.data["microscopes"][microscope][hardware_type])): galvo_keys = self.data["microscopes"][microscope][hardware_type][ i ].keys() for key in galvo_keys: if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][i][ key ], ) else: self.assertIn(key, expected_keys) else: raise ValueError("Galvo section is not a list") def filter_wheel_section(self, microscope, hardware_type): expected_keys = [ "hardware", "filter_wheel_delay", "available_filters", ] type_keys = ["type", "wheel_number", "port", "baudrate"] keys = self.data["microscopes"][microscope][hardware_type].keys() for key in keys: if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) elif key == "available_filters": assert isinstance( self.data["microscopes"][microscope][hardware_type][key], dict ) else: self.assertIn(key, expected_keys) def stage_section(self, microscope, hardware_type): expected_keys = [ "hardware", "x_max", "x_min", "y_max", "y_min", "z_max", "z_min", "f_max", "f_min", "theta_max", "theta_min", "x_offset", "y_offset", "z_offset", "theta_offset", "f_offset", "joystick_axes", "flip_x", "flip_y", "flip_z", "flip_f", ] type_keys = [ "type", "serial_number", "axes", "volts_per_micron", "axes_mapping", "max", "min", "controllername", "stages", "refmode", "port", "baudrate", "timeout", ] for key in self.data["microscopes"][microscope][hardware_type].keys(): if key == "hardware": if isinstance( self.data["microscopes"][microscope][hardware_type][key], list ): for i in range( len(self.data["microscopes"][microscope][hardware_type][key]) ): for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][ key ][i], ) elif isinstance( self.data["microscopes"][microscope][hardware_type][key], dict ): for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) else: raise ValueError("Stage hardware is not a list or dict") else: self.assertIn(key, expected_keys) def zoom_section(self, microscope, hardware_type): expected_keys = ["hardware", "position", "pixel_size", "stage_positions"] type_keys = ["type", "servo_id", "port", "baudrate"] for key in self.data["microscopes"][microscope][hardware_type].keys(): if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) elif key == "position": assert isinstance( self.data["microscopes"][microscope][hardware_type][key], dict ) elif key == "pixel_size": assert isinstance( self.data["microscopes"][microscope][hardware_type][key], dict ) elif key == "stage_positions": assert isinstance( self.data["microscopes"][microscope][hardware_type][key], dict ) else: self.assertIn(key, expected_keys) def shutter_section(self, microscope, hardware_type): expected_keys = ["hardware"] type_keys = ["type", "channel", "min", "max"] for key in self.data["microscopes"][microscope][hardware_type].keys(): if key == "hardware": for type_key in type_keys: self.assertIn( type_key, self.data["microscopes"][microscope][hardware_type][key], ) else: self.assertIn(key, expected_keys) def laser_section(self, microscope, hardware_type): expected_keys = [ "wavelength", "onoff", "power", "type", ] hardware_keys = ["type", "channel", "min", "max"] if isinstance(self.data["microscopes"][microscope][hardware_type], list): for i in range(len(self.data["microscopes"][microscope][hardware_type])): laser_keys = self.data["microscopes"][microscope][hardware_type][ i ].keys() for key in laser_keys: if key == "onoff" or key == "power": onoff_keys = self.data["microscopes"][microscope][ hardware_type ][i][key]["hardware"].keys() for onoff_key in onoff_keys: self.assertIn(onoff_key, hardware_keys) else: self.assertIn(key, expected_keys) else: raise ValueError("Laser section is not a list")