163 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright 2013-2016 DataStax, Inc.
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| # http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| import sys
 | |
| 
 | |
| from cassandra.marshal import bitlength
 | |
| from cassandra.protocol import MAX_SUPPORTED_VERSION
 | |
| 
 | |
| try:
 | |
|     import unittest2 as unittest
 | |
| except ImportError:
 | |
|     import unittest  # noqa
 | |
| 
 | |
| import platform
 | |
| from datetime import datetime, date
 | |
| from decimal import Decimal
 | |
| from uuid import UUID
 | |
| 
 | |
| from cassandra.cqltypes import lookup_casstype, DecimalType, UTF8Type, DateType
 | |
| from cassandra.util import OrderedMapSerializedKey, sortedset, Time, Date
 | |
| 
 | |
| marshalled_value_pairs = (
 | |
|     # binary form, type, python native type
 | |
|     (b'lorem ipsum dolor sit amet', 'AsciiType', 'lorem ipsum dolor sit amet'),
 | |
|     (b'', 'AsciiType', ''),
 | |
|     (b'\x01', 'BooleanType', True),
 | |
|     (b'\x00', 'BooleanType', False),
 | |
|     (b'', 'BooleanType', None),
 | |
|     (b'\xff\xfe\xfd\xfc\xfb', 'BytesType', b'\xff\xfe\xfd\xfc\xfb'),
 | |
|     (b'', 'BytesType', b''),
 | |
|     (b'\x7f\xff\xff\xff\xff\xff\xff\xff', 'CounterColumnType', 9223372036854775807),
 | |
|     (b'\x80\x00\x00\x00\x00\x00\x00\x00', 'CounterColumnType', -9223372036854775808),
 | |
|     (b'', 'CounterColumnType', None),
 | |
|     (b'\x00\x00\x013\x7fb\xeey', 'DateType', datetime(2011, 11, 7, 18, 55, 49, 881000)),
 | |
|     (b'\x00\x00\x01P\xc5~L\x00', 'DateType', datetime(2015, 11, 2)),
 | |
|     (b'', 'DateType', None),
 | |
|     (b'\x00\x00\x00\r\nJ\x04"^\x91\x04\x8a\xb1\x18\xfe', 'DecimalType', Decimal('1243878957943.1234124191998')),
 | |
|     (b'\x00\x00\x00\x06\xe5\xde]\x98Y', 'DecimalType', Decimal('-112233.441191')),
 | |
|     (b'\x00\x00\x00\x14\x00\xfa\xce', 'DecimalType', Decimal('0.00000000000000064206')),
 | |
|     (b'\x00\x00\x00\x14\xff\x052', 'DecimalType', Decimal('-0.00000000000000064206')),
 | |
|     (b'\xff\xff\xff\x9c\x00\xfa\xce', 'DecimalType', Decimal('64206e100')),
 | |
|     (b'', 'DecimalType', None),
 | |
|     (b'@\xd2\xfa\x08\x00\x00\x00\x00', 'DoubleType', 19432.125),
 | |
|     (b'\xc0\xd2\xfa\x08\x00\x00\x00\x00', 'DoubleType', -19432.125),
 | |
|     (b'\x7f\xef\x00\x00\x00\x00\x00\x00', 'DoubleType', 1.7415152243978685e+308),
 | |
|     (b'', 'DoubleType', None),
 | |
|     (b'F\x97\xd0@', 'FloatType', 19432.125),
 | |
|     (b'\xc6\x97\xd0@', 'FloatType', -19432.125),
 | |
|     (b'\xc6\x97\xd0@', 'FloatType', -19432.125),
 | |
|     (b'\x7f\x7f\x00\x00', 'FloatType', 338953138925153547590470800371487866880.0),
 | |
|     (b'', 'FloatType', None),
 | |
|     (b'\x7f\x50\x00\x00', 'Int32Type', 2135949312),
 | |
|     (b'\xff\xfd\xcb\x91', 'Int32Type', -144495),
 | |
|     (b'', 'Int32Type', None),
 | |
|     (b'f\x1e\xfd\xf2\xe3\xb1\x9f|\x04_\x15', 'IntegerType', 123456789123456789123456789),
 | |
|     (b'', 'IntegerType', None),
 | |
|     (b'\x7f\xff\xff\xff\xff\xff\xff\xff', 'LongType', 9223372036854775807),
 | |
|     (b'\x80\x00\x00\x00\x00\x00\x00\x00', 'LongType', -9223372036854775808),
 | |
|     (b'', 'LongType', None),
 | |
|     (b'', 'InetAddressType', None),
 | |
|     (b'A46\xa9', 'InetAddressType', '65.52.54.169'),
 | |
|     (b'*\x00\x13(\xe1\x02\xcc\xc0\x00\x00\x00\x00\x00\x00\x01"', 'InetAddressType', '2a00:1328:e102:ccc0::122'),
 | |
|     (b'\xe3\x81\xbe\xe3\x81\x97\xe3\x81\xa6', 'UTF8Type', u'\u307e\u3057\u3066'),
 | |
|     (b'\xe3\x81\xbe\xe3\x81\x97\xe3\x81\xa6' * 1000, 'UTF8Type', u'\u307e\u3057\u3066' * 1000),
 | |
|     (b'', 'UTF8Type', u''),
 | |
|     (b'\xff' * 16, 'UUIDType', UUID('ffffffff-ffff-ffff-ffff-ffffffffffff')),
 | |
|     (b'I\x15~\xfc\xef<\x9d\xe3\x16\x98\xaf\x80\x1f\xb4\x0b*', 'UUIDType', UUID('49157efc-ef3c-9de3-1698-af801fb40b2a')),
 | |
|     (b'', 'UUIDType', None),
 | |
|     (b'', 'MapType(AsciiType, BooleanType)', None),
 | |
|     (b'', 'ListType(FloatType)', None),
 | |
|     (b'', 'SetType(LongType)', None),
 | |
|     (b'\x00\x00', 'MapType(DecimalType, BooleanType)', OrderedMapSerializedKey(DecimalType, 0)),
 | |
|     (b'\x00\x00', 'ListType(FloatType)', []),
 | |
|     (b'\x00\x00', 'SetType(IntegerType)', sortedset()),
 | |
|     (b'\x00\x01\x00\x10\xafYC\xa3\xea<\x11\xe1\xabc\xc4,\x03"y\xf0', 'ListType(TimeUUIDType)', [UUID(bytes=b'\xafYC\xa3\xea<\x11\xe1\xabc\xc4,\x03"y\xf0')]),
 | |
|     (b'\x80\x00\x00\x01', 'SimpleDateType', Date(1)),
 | |
|     (b'\x7f\xff\xff\xff', 'SimpleDateType', Date('1969-12-31')),
 | |
|     (b'\x00\x00\x00\x00\x00\x00\x00\x01', 'TimeType', Time(1)),
 | |
|     (b'\x7f', 'ByteType', 127),
 | |
|     (b'\x80', 'ByteType', -128),
 | |
|     (b'\x7f\xff', 'ShortType', 32767),
 | |
|     (b'\x80\x00', 'ShortType', -32768)
 | |
| )
 | |
| 
 | |
| ordered_map_value = OrderedMapSerializedKey(UTF8Type, 2)
 | |
| ordered_map_value._insert(u'\u307fbob', 199)
 | |
| ordered_map_value._insert(u'', -1)
 | |
| ordered_map_value._insert(u'\\', 0)
 | |
| 
 | |
| # these following entries work for me right now, but they're dependent on
 | |
| # vagaries of internal python ordering for unordered types
 | |
| marshalled_value_pairs_unsafe = (
 | |
|     (b'\x00\x03\x00\x06\xe3\x81\xbfbob\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x04\xff\xff\xff\xff\x00\x01\\\x00\x04\x00\x00\x00\x00', 'MapType(UTF8Type, Int32Type)', ordered_map_value),
 | |
|     (b'\x00\x02\x00\x08@\x01\x99\x99\x99\x99\x99\x9a\x00\x08@\x14\x00\x00\x00\x00\x00\x00', 'SetType(DoubleType)', sortedset([2.2, 5.0])),
 | |
|     (b'\x00', 'IntegerType', 0),
 | |
| )
 | |
| 
 | |
| if platform.python_implementation() == 'CPython':
 | |
|     # Only run tests for entries which depend on internal python ordering under
 | |
|     # CPython
 | |
|     marshalled_value_pairs += marshalled_value_pairs_unsafe
 | |
| 
 | |
| 
 | |
| class UnmarshalTest(unittest.TestCase):
 | |
|     def test_unmarshalling(self):
 | |
|         for serializedval, valtype, nativeval in marshalled_value_pairs:
 | |
|             unmarshaller = lookup_casstype(valtype)
 | |
|             whatwegot = unmarshaller.from_binary(serializedval, 1)
 | |
|             self.assertEqual(whatwegot, nativeval,
 | |
|                              msg='Unmarshaller for %s (%s) failed: unmarshal(%r) got %r instead of %r'
 | |
|                                  % (valtype, unmarshaller, serializedval, whatwegot, nativeval))
 | |
|             self.assertEqual(type(whatwegot), type(nativeval),
 | |
|                              msg='Unmarshaller for %s (%s) gave wrong type (%s instead of %s)'
 | |
|                                  % (valtype, unmarshaller, type(whatwegot), type(nativeval)))
 | |
| 
 | |
|     def test_marshalling(self):
 | |
|         for serializedval, valtype, nativeval in marshalled_value_pairs:
 | |
|             marshaller = lookup_casstype(valtype)
 | |
|             whatwegot = marshaller.to_binary(nativeval, 1)
 | |
|             self.assertEqual(whatwegot, serializedval,
 | |
|                              msg='Marshaller for %s (%s) failed: marshal(%r) got %r instead of %r'
 | |
|                                  % (valtype, marshaller, nativeval, whatwegot, serializedval))
 | |
|             self.assertEqual(type(whatwegot), type(serializedval),
 | |
|                              msg='Marshaller for %s (%s) gave wrong type (%s instead of %s)'
 | |
|                                  % (valtype, marshaller, type(whatwegot), type(serializedval)))
 | |
| 
 | |
|     def test_bitlength(self):
 | |
|         self.assertEqual(bitlength(9), 4)
 | |
|         self.assertEqual(bitlength(-10), 0)
 | |
|         self.assertEqual(bitlength(0), 0)
 | |
| 
 | |
|     def test_date(self):
 | |
|         # separate test because it will deserialize as datetime
 | |
|         self.assertEqual(DateType.from_binary(DateType.to_binary(date(2015, 11, 2), 1), 1), datetime(2015, 11, 2))
 | |
| 
 | |
|     def test_decimal(self):
 | |
|         # testing implicit numeric conversion
 | |
|         # int, tuple(sign, digits, exp), float
 | |
|         converted_types = (10001, (0, (1, 0, 0, 0, 0, 1), -3), 100.1)
 | |
| 
 | |
|         if sys.version_info < (2, 7):
 | |
|             # Decimal in Python 2.6 does not accept floats for lossless initialization
 | |
|             # Just verifying expected exception here
 | |
|             f = converted_types[-1]
 | |
|             self.assertIsInstance(f, float)
 | |
|             self.assertRaises(TypeError, DecimalType.to_binary, f, MAX_SUPPORTED_VERSION)
 | |
|             converted_types = converted_types[:-1]
 | |
| 
 | |
|         for proto_ver in range(1, MAX_SUPPORTED_VERSION + 1):
 | |
|             for n in converted_types:
 | |
|                 expected = Decimal(n)
 | |
|                 self.assertEqual(DecimalType.from_binary(DecimalType.to_binary(n, proto_ver), proto_ver), expected)
 | 
