@@ -703,6 +703,102 @@ def test_invalid_json_string_raises(self):
703703 value = "[not-valid-json" ,
704704 )
705705
706+ @pytest .mark .parametrize (
707+ ("raw" , "expected" ),
708+ [
709+ ("true" , True ),
710+ ("True" , True ),
711+ ("TRUE" , True ),
712+ ("1" , True ),
713+ ("false" , False ),
714+ ("False" , False ),
715+ ("FALSE" , False ),
716+ ("0" , False ),
717+ ("" , False ),
718+ ("yes" , False ),
719+ ("no" , False ),
720+ ],
721+ )
722+ def test_boolean_string_casting (self , raw : str , expected : bool ):
723+ """Cloud API returns booleans as strings; only 'true'/'1' are truthy."""
724+ state = EventState (name = "state" , type = DataType .BOOLEAN , value = raw )
725+
726+ assert state .value is expected
727+
728+ def test_boolean_native_passthrough (self ):
729+ """Local API returns native booleans; they must not be re-cast."""
730+ true_state = EventState (name = "state" , type = DataType .BOOLEAN , value = True )
731+ false_state = EventState (name = "state" , type = DataType .BOOLEAN , value = False )
732+
733+ assert true_state .value is True
734+ assert false_state .value is False
735+
736+ @pytest .mark .parametrize (
737+ ("raw" , "data_type" , "expected" ),
738+ [
739+ ("42" , DataType .INTEGER , 42 ),
740+ ("-1" , DataType .INTEGER , - 1 ),
741+ ("0" , DataType .INTEGER , 0 ),
742+ ("3.14" , DataType .FLOAT , pytest .approx (3.14 )),
743+ ("-1.5" , DataType .FLOAT , pytest .approx (- 1.5 )),
744+ ("0.0" , DataType .FLOAT , pytest .approx (0.0 )),
745+ ("0" , DataType .FLOAT , pytest .approx (0.0 )),
746+ ("12345" , DataType .DATE , 12345 ),
747+ ("0" , DataType .DATE , 0 ),
748+ ("[1, 2]" , DataType .JSON_ARRAY , [1 , 2 ]),
749+ ("[]" , DataType .JSON_ARRAY , []),
750+ ('{"foo": 1}' , DataType .JSON_OBJECT , {"foo" : 1 }),
751+ ("{}" , DataType .JSON_OBJECT , {}),
752+ ],
753+ )
754+ def test_other_type_casting (self , raw : str , data_type : DataType , expected ):
755+ """Non-boolean string values are cast correctly."""
756+ state = EventState (name = "state" , type = data_type , value = raw )
757+
758+ assert state .value == expected
759+
760+ @pytest .mark .parametrize (
761+ ("raw" , "data_type" ),
762+ [
763+ ("abc" , DataType .INTEGER ),
764+ ("abc" , DataType .FLOAT ),
765+ ],
766+ )
767+ def test_invalid_numeric_string_raises (self , raw : str , data_type : DataType ):
768+ """Non-numeric strings raise ValueError for numeric types."""
769+ with pytest .raises (ValueError , match = "abc" ):
770+ EventState (name = "state" , type = data_type , value = raw )
771+
772+ def test_string_type_not_cast (self ):
773+ """STRING type values are left as-is, not passed through any caster."""
774+ state = EventState (name = "state" , type = DataType .STRING , value = "hello" )
775+
776+ assert state .value == "hello"
777+
778+ def test_empty_string_type_not_cast (self ):
779+ """Empty STRING type values are preserved."""
780+ state = EventState (name = "state" , type = DataType .STRING , value = "" )
781+
782+ assert state .value == ""
783+
784+ @pytest .mark .parametrize (
785+ ("value" , "data_type" ),
786+ [
787+ (42 , DataType .INTEGER ),
788+ (0 , DataType .INTEGER ),
789+ (3.14 , DataType .FLOAT ),
790+ (0.0 , DataType .FLOAT ),
791+ ({"foo" : 1 }, DataType .JSON_OBJECT ),
792+ ([1 , 2 ], DataType .JSON_ARRAY ),
793+ ],
794+ )
795+ def test_native_value_not_cast (self , value : object , data_type : DataType ):
796+ """Already-typed values (from local API) skip casting entirely."""
797+ state = EventState (name = "state" , type = data_type , value = value )
798+
799+ assert state .value == value
800+ assert type (state .value ) is type (value )
801+
706802
707803def test_command_to_payload_omits_none ():
708804 """Command.to_payload omits None fields from the resulting payload."""
0 commit comments