def test_GIVEN_an_existing_pv_WHEN_create_another_pv_of_same_name_THEN_append_numbers(self):
        # Arrange
        pv_01 = create_pv_name("Conf", [], "PEEVEE")

        # Act
        pv_02 = create_pv_name("Conf", [pv_01], "PEEVEE")

        # Assert
        self.assertEquals(pv_01, "CONF")
        self.assertEquals(pv_02, "CONF01")
    def test_GIVEN_a_long_pv_WHEN_create_pv_with_same_name_and_invalid_chars_THEN_remove_invalid_chars_and_truncate_and_number_correctly(
        self
    ):
        # Arrange
        pv_01 = create_pv_name("Configuration", [], "PEEVEE")

        # Act
        pv_02 = create_pv_name("Co*&^nfiguration", [pv_01], "PEEVEE")

        # Assert
        self.assertEquals(pv_01, "CONFIG")
        self.assertEquals(pv_02, "CONF01")
    def test_GIVEN_an_existing_truncated_pv_WHEN_another_pv_of_same_name_THEN_truncate_and_rename_differently(self):
        # Arrange
        pv_01 = create_pv_name("Configuration", [], "PEEVEE")

        # Act
        pv_02 = create_pv_name("Configuration", [pv_01], "PEEVEE")
        pv_03 = create_pv_name("Configuration", [pv_01, pv_02], "PEEVEE")

        # Assert
        self.assertEquals(pv_01, "CONFIG")
        self.assertEquals(pv_02, "CONF01")
        self.assertEquals(pv_03, "CONF02")
    def test_GIVEN_blank_pv_name_WHEN_another_blank_pv_name_THEN_append_numbers(self):
        # Arrange
        pv_01 = create_pv_name("", [], "PEEVEE")

        # Act
        pv_02 = create_pv_name("", [pv_01], "PEEVEE")
        pv_03 = create_pv_name("", [pv_01, pv_02], "PEEVEE")

        # Assert
        self.assertEquals(pv_01, "PEEVEE")
        self.assertEquals(pv_02, "PEEV01")
        self.assertEquals(pv_03, "PEEV02")
 def _get_pv_name(self, config_name, is_component=False):
     """Returns the name of the pv corresponding to config_name, this name is generated if not already created."""
     if not is_component:
         if config_name in self._config_metas:
             pv_name = self._config_metas[config_name].pv
         else:
             curr_pvs = [meta.pv for meta in self._config_metas.values()]
             pv_name = create_pv_name(config_name, curr_pvs, "CONFIG")
     else:
         if config_name in self._component_metas:
             pv_name = self._component_metas[config_name].pv
         else:
             curr_pvs = [meta.pv for meta in self._component_metas.values()]
             pv_name = create_pv_name(config_name, curr_pvs, "COMPONENT")
     return pv_name
    def _create_pvs(self, pv_names, suffix=""):
        pvs = list()
        for name in pv_names:
            pvs.append(create_pv_name(name, pvs, "DEFAULT"))

        pvs = [pv + suffix for pv in pvs]
        return pvs
    def test_add_a_new_component_to_list(self):
        self.icm = self._create_inactive_config_holder()
        self.icm.set_config_details(VALID_CONFIG)
        self.clm.update_a_config_in_list(self.icm, True)

        confs = self.clm.get_components()
        self.assertEqual(len(confs), 1)
        self.assertTrue("TEST_CONFIG" in [conf.get('name') for conf in confs])
        self.assertTrue(create_pv_name("TEST_CONFIG", [], "") in [conf.get('pv') for conf in confs])
        self.assertTrue("A Test Configuration" in [conf.get('description') for conf in confs])
        self.assertTrue("TEST_SYNOPTIC" in [conf.get('synoptic') for conf in confs])

        comps = self.clm.get_configs()
        self.assertEqual(len(comps), 0)
    def _create_pv(self, data):
        """Creates a single PV based on a name and data. Adds this PV to the dictionary returned on get_synoptic_list

        Args:
            data (string): Starting data for the pv, the pv name is derived from the name tag of this
        """
        name = self._get_synoptic_name_from_xml(data)
        if name not in self._synoptic_pvs:
            # Extra check, if a non-case sensitive match exist remove it
            for key in self._synoptic_pvs.keys():
                if name.lower() == key.lower():
                    self._synoptic_pvs.pop(key)
            pv = create_pv_name(name, self._synoptic_pvs.values(), "SYNOPTIC")
            self._synoptic_pvs[name] = pv

        # Create the PV
        self._bs.add_string_pv_to_db(SYNOPTIC_PRE + self._synoptic_pvs[name] + SYNOPTIC_GET, 16000)
        # Update the value
        self.update_pv_value(SYNOPTIC_PRE + self._synoptic_pvs[name] + SYNOPTIC_GET, compress_and_hex(data))
    def _add_constants_pvs(self):
        """
        Add pvs for the beamline constants
        """

        beamline_constant_info = []

        for beamline_constant in self._beamline.beamline_constants:
            try:
                const_alias = create_pv_name(beamline_constant.name, list(self.PVDB.keys()), CONST_PREFIX,
                                             limit=20, allow_colon=True)
                prepended_alias = "{}:{}".format(CONST_PREFIX, const_alias)

                if isinstance(beamline_constant.value, bool):
                    value = 1 if bool(beamline_constant.value) else 0
                    fields = PARAM_FIELDS_BINARY
                elif isinstance(beamline_constant.value, str):
                    value = beamline_constant.value
                    fields = STANDARD_2048_CHAR_WF_FIELDS
                else:
                    value = float(beamline_constant.value)
                    fields = STANDARD_FLOAT_PV_FIELDS

                self._add_pv_with_fields(prepended_alias, None, fields, beamline_constant.description, None,
                                         interest="MEDIUM", value=value)
                logger.info("Adding Constant {} with value {}".format(beamline_constant.name, beamline_constant.value))
                beamline_constant_info.append(
                    {"name": beamline_constant.name,
                     "prepended_alias": prepended_alias,
                     "type": "float_value",
                     "description": beamline_constant.description})
            except Exception as err:
                STATUS_MANAGER.update_error_log("Error adding constant {}: {}".format(beamline_constant.name, err), err)
                STATUS_MANAGER.update_active_problems(
                    ProblemInfo("Error adding PV for beamline constant", beamline_constant.name, Severity.MAJOR_ALARM))

        self._add_pv_with_fields(BEAMLINE_CONSTANT_INFO, None, STANDARD_2048_CHAR_WF_FIELDS, "All value parameters",
                                 None, value=compress_and_hex(json.dumps(beamline_constant_info)))
    def _add_all_driver_pvs(self):
        """
        Add all pvs for the drivers.
        """
        self.drivers_pv = {}
        driver_info = []
        for driver in self._beamline.drivers:
            if driver.has_engineering_correction:
                correction_alias = create_pv_name(driver.name, list(self.PVDB.keys()), "COR", limit=12,
                                                  allow_colon=True)
                prepended_alias = "{}:{}".format("COR", correction_alias)

                self._add_pv_with_fields(prepended_alias, None, STANDARD_FLOAT_PV_FIELDS, "Engineering Correction",
                                         None, archive=True)
                self._add_pv_with_fields("{}:DESC".format(prepended_alias), None, STANDARD_2048_CHAR_WF_FIELDS,
                                         "Engineering Correction Full Description", None)

                self.drivers_pv[driver] = prepended_alias

                driver_info.append({"name": driver.name, "prepended_alias": prepended_alias})

        self._add_pv_with_fields(DRIVER_INFO, None, STANDARD_2048_CHAR_WF_FIELDS, "All corrections information",
                                 None, value=compress_and_hex(json.dumps(driver_info)))
    def test_WHEN_pv_name_too_long_THEN_truncate_to_six_chars(self):
        # Act
        pv = create_pv_name("Configuration", [], "PEEVEE")

        # Assert
        self.assertEquals(pv, "CONFIG")
    def test_WHEN_pv_name_is_blank_THEN_replace_pv_with_default_pv_name(self):
        # Act
        pv = create_pv_name("", [], "PEEVEE")

        # Assert
        self.assertEquals(pv, "PEEVEE")
    def test_WHEN_pv_name_contains_only_numbers_and_underscores_THEN_replace_pv_with_default_pv_name(self):
        # Act
        pv = create_pv_name("1_2_3_4", [], "PEEVEE")

        # Assert
        self.assertEquals(pv, "PEEVEE")
    def test_WHEN_pv_name_contains_non_alphanumeric_characters_THEN_remove_non_alphanumeric_characters(self):
        # Act
        pv = create_pv_name("c-onf@ig", [], "PEEVEE")

        # Assert
        self.assertEquals(pv, "CONFIG")
    def test_WHEN_pv_name_contains_whitespace_THEN_replace_whitespace_with_underscore(self):
        # Act
        pv = create_pv_name("config name", [], "PEEVEE")

        # Assert
        self.assertEquals(pv, "CONFIG")
 def test_pv_of_lower_case_name(self):
     config_name = "test_CONfig1"
     self._check_pv_changed_but_not_name(config_name, create_pv_name(config_name, [], ""))
    def _add_parameter_pvs(self, parameter):
        """
        Adds all PVs needed for one beamline parameter to the PV database.

        Args:
            parameter (ReflectometryServer.parameters.BeamlineParameter): the beamline parameter

        Returns:
            parameter information
        """
        param_name = parameter.name
        description = parameter.description
        param_alias = create_pv_name(param_name, list(self.PVDB.keys()), PARAM_PREFIX, limit=10)
        prepended_alias = "{}:{}".format(PARAM_PREFIX, param_alias)

        parameter_type = parameter.parameter_type
        fields = PARAMS_FIELDS_BEAMLINE_TYPES[parameter_type].copy()
        fields["unit"] = parameter.engineering_unit
        if parameter_type == BeamlineParameterType.ENUM:
            fields["enums"] = parameter.options

        # Readback PV
        self._add_pv_with_fields(prepended_alias, param_name, fields, description, PvSort.RBV, archive=True,
                                 interest="HIGH")

        # Setpoint PV
        self._add_pv_with_fields(prepended_alias + SP_SUFFIX, param_name, fields, description, PvSort.SP,
                                 archive=True)

        # Setpoint readback PV
        self._add_pv_with_fields(prepended_alias + SP_RBV_SUFFIX, param_name, fields, description, PvSort.SP_RBV)

        # Set value and do not action PV
        self._add_pv_with_fields(prepended_alias + SET_AND_NO_ACTION_SUFFIX, param_name, fields, description,
                                 PvSort.SET_AND_NO_ACTION, is_disabled_on_init=parameter.sp_mirrors_rbv)

        # Changed PV
        self._add_pv_with_fields(prepended_alias + CHANGED_SUFFIX, param_name, PARAM_FIELDS_BINARY, description,
                                 PvSort.CHANGED)

        # Action PV
        self._add_pv_with_fields(prepended_alias + ACTION_SUFFIX, param_name, PARAM_FIELDS_ACTION, description,
                                 PvSort.ACTION)

        # Moving state PV
        self._add_pv_with_fields(prepended_alias + CHANGING, param_name, PARAM_FIELDS_BINARY, description,
                                 PvSort.CHANGING)

        # In mode PV
        self._add_pv_with_fields(prepended_alias + IN_MODE_SUFFIX, param_name, PARAM_IN_MODE, description,
                                 PvSort.IN_MODE)

        # RBV to SP:RBV tolerance
        self._add_pv_with_fields(prepended_alias + RBV_AT_SP, param_name, PARAM_FIELDS_BINARY, description,
                                 PvSort.RBV_AT_SP)

        # define position at
        if parameter.define_current_value_as is not None:
            align_fields = STANDARD_FLOAT_PV_FIELDS.copy()
            align_fields["asg"] = "MANAGER"
            self._add_pv_with_fields(prepended_alias + DEFINE_POSITION_AS, param_name, align_fields, description,
                                     PvSort.DEFINE_POS_AS)

        # Engineering Unit
        egu_fields = STANDARD_STRING_FIELDS.copy()
        egu_fields["value"] = parameter.engineering_unit
        self.PVDB[prepended_alias + EGU_FIELD] = egu_fields

        return {"name": param_name,
                "prepended_alias": prepended_alias,
                "type": BeamlineParameterType.name_for_param_list(parameter_type),
                "characteristic_value": parameter.characteristic_value,
                "description": parameter.description}