@@ -578,15 +578,42 @@ def test_validate_derived_parameter(self) -> None:
578578 ):
579579 self .ss1 ._validate_derived_parameter (parameter = self .invalid_derived_param )
580580
581- # test with non-numeric param
581+ # test with non-numeric param used in arithmetic expression
582582 derived_param = DerivedParameter (
583- name = "z" , parameter_type = ParameterType .FLOAT , expression_str = "c"
583+ name = "z" , parameter_type = ParameterType .FLOAT , expression_str = "2.0 * c"
584584 )
585585 with self .assertRaisesRegex (
586586 ValueError ,
587587 "Parameter c is not a float or int, but is used in a derived parameter." ,
588588 ):
589589 self .ss1 ._validate_derived_parameter (parameter = derived_param )
590+
591+ # test simple copy type incompatibility: numeric derived from non-numeric source
592+ # tests the unified type compatibility rule: types must match OR both numeric
593+ derived_param = DerivedParameter (
594+ name = "z" , parameter_type = ParameterType .FLOAT , expression_str = "c"
595+ )
596+ with self .assertRaisesRegex (
597+ ValueError ,
598+ "Parameter c has type STRING, but the derived parameter has type FLOAT. "
599+ "Simple copy derived parameters must have the same type as their source "
600+ "parameter." ,
601+ ):
602+ self .ss1 ._validate_derived_parameter (parameter = derived_param )
603+
604+ # test simple copy type incompatibility: non-numeric derived from numeric source
605+ # same validation rule as above, different type combination
606+ derived_param = DerivedParameter (
607+ name = "z" , parameter_type = ParameterType .STRING , expression_str = "a"
608+ )
609+ with self .assertRaisesRegex (
610+ ValueError ,
611+ "Parameter a has type FLOAT, but the derived parameter has type STRING. "
612+ "Simple copy derived parameters must have the same type as their source "
613+ "parameter." ,
614+ ):
615+ self .ss1 ._validate_derived_parameter (parameter = derived_param )
616+
590617 # test int derived param with float constituent param
591618 derived_param = DerivedParameter (
592619 name = "z" , parameter_type = ParameterType .INT , expression_str = "a"
@@ -597,6 +624,16 @@ def test_validate_derived_parameter(self) -> None:
597624 ):
598625 self .ss1 ._validate_derived_parameter (parameter = derived_param )
599626
627+ # test int derived param with float constituent param (arithmetic expression)
628+ derived_param = DerivedParameter (
629+ name = "z" , parameter_type = ParameterType .INT , expression_str = "2.0 * a"
630+ )
631+ with self .assertRaisesRegex (
632+ ValueError ,
633+ "Parameter a is a float, but is used in a derived parameter with int type." ,
634+ ):
635+ self .ss1 ._validate_derived_parameter (parameter = derived_param )
636+
600637 # test derived param with constituent derived param
601638 derived_param = DerivedParameter (
602639 name = "z" , parameter_type = ParameterType .FLOAT , expression_str = "h"
@@ -621,6 +658,37 @@ def test_validate_derived_parameter(self) -> None:
621658 ):
622659 self .ss1 ._validate_derived_parameter (parameter = derived_param )
623660
661+ # test simple copy of STRING parameter - should succeed
662+ string_derived_param = DerivedParameter (
663+ name = "derived_c" , parameter_type = ParameterType .STRING , expression_str = "c"
664+ )
665+ # This should NOT raise - it's a valid simple copy
666+ self .ss1 ._validate_derived_parameter (parameter = string_derived_param )
667+
668+ # test simple copy of BOOL parameter - should succeed
669+ # Add a non-fixed BOOL parameter to the search space
670+ bool_choice_param = ChoiceParameter (
671+ name = "bool_choice" , parameter_type = ParameterType .BOOL , values = [True , False ]
672+ )
673+ self .ss1 .add_parameter (bool_choice_param )
674+ bool_derived_param = DerivedParameter (
675+ name = "derived_bool" ,
676+ parameter_type = ParameterType .BOOL ,
677+ expression_str = "bool_choice" ,
678+ )
679+ # This should NOT raise - it's a valid simple copy
680+ self .ss1 ._validate_derived_parameter (parameter = bool_derived_param )
681+
682+ # test simple copy INT to FLOAT promotion - should succeed
683+ # INT can be promoted to FLOAT (e.g., 3 -> 3.0)
684+ int_to_float_derived_param = DerivedParameter (
685+ name = "derived_f_as_float" ,
686+ parameter_type = ParameterType .FLOAT ,
687+ expression_str = "f" , # f is an INT parameter
688+ )
689+ # This should NOT raise - INT can be promoted to FLOAT
690+ self .ss1 ._validate_derived_parameter (parameter = int_to_float_derived_param )
691+
624692 def test_get_overlapping_parameters (self ) -> None :
625693 with self .subTest ("full_overlap" ):
626694 range_param_1 = RangeParameter (
0 commit comments