@@ -706,3 +706,131 @@ def test__from_dict(self):
706706 assert len (instance .mutations ) == 1
707707 assert isinstance (instance .mutations [0 ], mutations .DeleteAllFromFamily )
708708 assert instance .mutations [0 ].family_to_delete == "test_family"
709+
710+
711+ class TestAddToCell :
712+ def _target_class (self ):
713+ from google .cloud .bigtable .data .mutations import AddToCell
714+
715+ return AddToCell
716+
717+ def _make_one (self , * args , ** kwargs ):
718+ return self ._target_class ()(* args , ** kwargs )
719+
720+ @pytest .mark .parametrize ("input_val" , [2 ** 64 , - (2 ** 64 )])
721+ def test_ctor_large_int (self , input_val ):
722+ with pytest .raises (ValueError ) as e :
723+ self ._make_one (family = "f" , qualifier = b"b" , value = input_val )
724+ assert "int values must be between" in str (e .value )
725+
726+ @pytest .mark .parametrize ("input_val" , ["" , "a" , "abc" , "hello world!" ])
727+ def test_ctor_str_value (self , input_val ):
728+ with pytest .raises (ValueError ) as e :
729+ self ._make_one (family = "f" , qualifier = b"b" , value = input_val )
730+ assert "value must be int" in str (e .value )
731+
732+ def test_ctor (self ):
733+ """Ensure constructor sets expected values"""
734+ expected_family = "test-family"
735+ expected_qualifier = b"test-qualifier"
736+ expected_value = 1234
737+ expected_timestamp = 1234567890
738+ instance = self ._make_one (
739+ expected_family , expected_qualifier , expected_value , expected_timestamp
740+ )
741+ assert instance .family == expected_family
742+ assert instance .qualifier == expected_qualifier
743+ assert instance .value == expected_value
744+ assert instance .timestamp_micros == expected_timestamp
745+
746+ def test_ctor_negative_timestamp (self ):
747+ """Only positive or -1 timestamps are valid"""
748+ with pytest .raises (ValueError ) as e :
749+ self ._make_one ("test-family" , b"test-qualifier" , b"test-value" , - 2 )
750+ assert (
751+ "timestamp_micros must be positive (or -1 for server-side timestamp)"
752+ in str (e .value )
753+ )
754+
755+ @pytest .mark .parametrize (
756+ "timestamp_ns,expected_timestamp_micros" ,
757+ [
758+ (0 , 0 ),
759+ (1 , 0 ),
760+ (123 , 0 ),
761+ (999 , 0 ),
762+ (999_999 , 0 ),
763+ (1_000_000 , 1000 ),
764+ (1_234_567 , 1000 ),
765+ (1_999_999 , 1000 ),
766+ (2_000_000 , 2000 ),
767+ (1_234_567_890_123 , 1_234_567_000 ),
768+ ],
769+ )
770+ def test_ctor_no_timestamp (self , timestamp_ns , expected_timestamp_micros ):
771+ """If no timestamp is given, should use current time with millisecond precision"""
772+ with mock .patch ("time.time_ns" , return_value = timestamp_ns ):
773+ instance = self ._make_one ("test-family" , b"test-qualifier" , 1234 )
774+ assert instance .timestamp_micros == expected_timestamp_micros
775+
776+ def test__to_dict (self ):
777+ """ensure dict representation is as expected"""
778+ expected_family = "test-family"
779+ expected_qualifier = b"test-qualifier"
780+ expected_value = 1234
781+ expected_timestamp = 123456789
782+ instance = self ._make_one (
783+ expected_family , expected_qualifier , expected_value , expected_timestamp
784+ )
785+ got_dict = instance ._to_dict ()
786+ assert list (got_dict .keys ()) == ["add_to_cell" ]
787+ got_inner_dict = got_dict ["add_to_cell" ]
788+ assert got_inner_dict ["family_name" ] == expected_family
789+ assert got_inner_dict ["column_qualifier" ]["raw_value" ] == expected_qualifier
790+ assert got_inner_dict ["timestamp_micros" ]["raw_timestamp_micros" ] == expected_timestamp
791+ assert got_inner_dict ["value" ]["int_value" ] == expected_value
792+ assert len (got_inner_dict .keys ()) == 4
793+
794+ def test__to_pb (self ):
795+ """ensure proto representation is as expected"""
796+ import google .cloud .bigtable_v2 .types .data as data_pb
797+
798+ expected_family = "test-family"
799+ expected_qualifier = b"test-qualifier"
800+ expected_value = 1234
801+ expected_timestamp = 123456789
802+ instance = self ._make_one (
803+ expected_family , expected_qualifier , expected_value , expected_timestamp
804+ )
805+ got_pb = instance ._to_pb ()
806+ assert isinstance (got_pb , data_pb .Mutation )
807+ assert got_pb .set_cell .family_name == expected_family
808+ assert got_pb .set_cell .column_qualifier .raw_value == expected_qualifier
809+ assert got_pb .set_cell .timestamp_micros .raw_timestamp_micros == expected_timestamp
810+ assert got_pb .set_cell .value .int_value == expected_value
811+
812+ @pytest .mark .parametrize (
813+ "timestamp" ,
814+ [
815+ (1234567890 ),
816+ (1 ),
817+ (0 ),
818+ (- 1 ),
819+ (None ),
820+ ],
821+ )
822+ def test_is_idempotent (self , timestamp , expected_value ):
823+ """is_idempotent is not based on whether an explicit timestamp is set"""
824+ instance = self ._make_one (
825+ "test-family" , b"test-qualifier" , 1234 , timestamp
826+ )
827+ assert not instance .is_idempotent ()
828+
829+ def test___str__ (self ):
830+ """Str representation of mutations should be to_dict"""
831+ instance = self ._make_one (
832+ "test-family" , b"test-qualifier" , 1234 , 1234567890
833+ )
834+ str_value = instance .__str__ ()
835+ dict_value = instance ._to_dict ()
836+ assert str_value == str (dict_value )
0 commit comments