fune/third_party/python/cbor2/tests/test_decoder.py
David Keeler 0bfa8aad3f bug 1421816 - (1/2) add cbor2 library r=ted
This library will be used to create test COSE signatures for the new COSE add-on
signature verification implementation.

MozReview-Commit-ID: KshKHwusT5h

--HG--
extra : rebase_source : 22d65622a77afc93b756829c8ffb4f37101dad26
extra : histedit_source : 869b9b65bdf201a027914a8127d28e5e9baf4d33
2017-11-29 10:57:37 -08:00

327 lines
9.6 KiB
Python

from __future__ import division
import math
import re
from binascii import unhexlify
from datetime import datetime, timedelta
from decimal import Decimal
from email.message import Message
from fractions import Fraction
from io import BytesIO
from uuid import UUID
import pytest
from cbor2.compat import timezone
from cbor2.decoder import loads, CBORDecodeError, load, CBORDecoder
from cbor2.types import CBORTag, undefined, CBORSimpleValue
@pytest.mark.parametrize('payload, expected', [
('00', 0),
('01', 1),
('0a', 10),
('17', 23),
('1818', 24),
('1819', 25),
('1864', 100),
('1903e8', 1000),
('1a000f4240', 1000000),
('1b000000e8d4a51000', 1000000000000),
('1bffffffffffffffff', 18446744073709551615),
('c249010000000000000000', 18446744073709551616),
('3bffffffffffffffff', -18446744073709551616),
('c349010000000000000000', -18446744073709551617),
('20', -1),
('29', -10),
('3863', -100),
('3903e7', -1000)
])
def test_integer(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
def test_invalid_integer_subtype():
exc = pytest.raises(CBORDecodeError, loads, b'\x1c')
assert str(exc.value).endswith('unknown unsigned integer subtype 0x1c')
@pytest.mark.parametrize('payload, expected', [
('f90000', 0.0),
('f98000', -0.0),
('f93c00', 1.0),
('fb3ff199999999999a', 1.1),
('f93e00', 1.5),
('f97bff', 65504.0),
('fa47c35000', 100000.0),
('fa7f7fffff', 3.4028234663852886e+38),
('fb7e37e43c8800759c', 1.0e+300),
('f90001', 5.960464477539063e-8),
('f90400', 0.00006103515625),
('f9c400', -4.0),
('fbc010666666666666', -4.1),
('f97c00', float('inf')),
('f9fc00', float('-inf')),
('fa7f800000', float('inf')),
('faff800000', float('-inf')),
('fb7ff0000000000000', float('inf')),
('fbfff0000000000000', float('-inf'))
])
def test_float(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload', ['f97e00', 'fa7fc00000', 'fb7ff8000000000000'])
def test_float_nan(payload):
decoded = loads(unhexlify(payload))
assert math.isnan(decoded)
@pytest.mark.parametrize('payload, expected', [
('f4', False),
('f5', True),
('f6', None),
('f7', undefined)
])
def test_special(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded is expected
@pytest.mark.parametrize('payload, expected', [
('40', b''),
('4401020304', b'\x01\x02\x03\x04'),
])
def test_binary(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('60', u''),
('6161', u'a'),
('6449455446', u'IETF'),
('62225c', u'\"\\'),
('62c3bc', u'\u00fc'),
('63e6b0b4', u'\u6c34')
])
def test_string(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('80', []),
('83010203', [1, 2, 3]),
('8301820203820405', [1, [2, 3], [4, 5]]),
('98190102030405060708090a0b0c0d0e0f101112131415161718181819', list(range(1, 26)))
])
def test_array(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('a0', {}),
('a201020304', {1: 2, 3: 4})
])
def test_map(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('a26161016162820203', {'a': 1, 'b': [2, 3]}),
('826161a161626163', ['a', {'b': 'c'}]),
('a56161614161626142616361436164614461656145',
{'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D', 'e': 'E'})
])
def test_mixed_array_map(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('5f42010243030405ff', b'\x01\x02\x03\x04\x05'),
('7f657374726561646d696e67ff', 'streaming'),
('9fff', []),
('9f018202039f0405ffff', [1, [2, 3], [4, 5]]),
('9f01820203820405ff', [1, [2, 3], [4, 5]]),
('83018202039f0405ff', [1, [2, 3], [4, 5]]),
('83019f0203ff820405', [1, [2, 3], [4, 5]]),
('9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff', list(range(1, 26))),
('bf61610161629f0203ffff', {'a': 1, 'b': [2, 3]}),
('826161bf61626163ff', ['a', {'b': 'c'}]),
('bf6346756ef563416d7421ff', {'Fun': True, 'Amt': -2}),
])
def test_streaming(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
@pytest.mark.parametrize('payload, expected', [
('e0', 0),
('e2', 2),
('f3', 19),
('f820', 32),
('e0', CBORSimpleValue(0)),
('e2', CBORSimpleValue(2)),
('f3', CBORSimpleValue(19)),
('f820', CBORSimpleValue(32))
])
def test_simple_value(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
#
# Tests for extension tags
#
@pytest.mark.parametrize('payload, expected', [
('c074323031332d30332d32315432303a30343a30305a',
datetime(2013, 3, 21, 20, 4, 0, tzinfo=timezone.utc)),
('c0781b323031332d30332d32315432303a30343a30302e3338303834315a',
datetime(2013, 3, 21, 20, 4, 0, 380841, tzinfo=timezone.utc)),
('c07819323031332d30332d32315432323a30343a30302b30323a3030',
datetime(2013, 3, 21, 22, 4, 0, tzinfo=timezone(timedelta(hours=2)))),
('c11a514b67b0', datetime(2013, 3, 21, 20, 4, 0, tzinfo=timezone.utc)),
('c11a514b67b0', datetime(2013, 3, 21, 22, 4, 0, tzinfo=timezone(timedelta(hours=2))))
], ids=['datetime/utc', 'datetime+micro/utc', 'datetime/eet', 'timestamp/utc', 'timestamp/eet'])
def test_datetime(payload, expected):
decoded = loads(unhexlify(payload))
assert decoded == expected
def test_bad_datetime():
exc = pytest.raises(CBORDecodeError, loads, unhexlify('c06b303030302d3132332d3031'))
assert str(exc.value).endswith('invalid datetime string: 0000-123-01')
def test_fraction():
decoded = loads(unhexlify('c48221196ab3'))
assert decoded == Decimal('273.15')
def test_bigfloat():
decoded = loads(unhexlify('c5822003'))
assert decoded == Decimal('1.5')
def test_rational():
decoded = loads(unhexlify('d81e820205'))
assert decoded == Fraction(2, 5)
def test_regex():
decoded = loads(unhexlify('d8236d68656c6c6f2028776f726c6429'))
expr = re.compile(u'hello (world)')
assert decoded == expr
def test_mime():
decoded = loads(unhexlify(
'd824787b436f6e74656e742d547970653a20746578742f706c61696e3b20636861727365743d2269736f2d38'
'3835392d3135220a4d494d452d56657273696f6e3a20312e300a436f6e74656e742d5472616e736665722d45'
'6e636f64696e673a2071756f7465642d7072696e7461626c650a0a48656c6c6f203d413475726f'))
assert isinstance(decoded, Message)
assert decoded.get_payload() == 'Hello =A4uro'
def test_uuid():
decoded = loads(unhexlify('d825505eaffac8b51e480581277fdcc7842faf'))
assert decoded == UUID(hex='5eaffac8b51e480581277fdcc7842faf')
def test_bad_shared_reference():
exc = pytest.raises(CBORDecodeError, loads, unhexlify('d81d05'))
assert str(exc.value).endswith('shared reference 5 not found')
def test_uninitialized_shared_reference():
fp = BytesIO(unhexlify('d81d00'))
decoder = CBORDecoder(fp)
decoder._shareables.append(None)
exc = pytest.raises(CBORDecodeError, decoder.decode)
assert str(exc.value).endswith('shared value 0 has not been initialized')
def test_cyclic_array():
decoded = loads(unhexlify('d81c81d81d00'))
assert decoded == [decoded]
def test_cyclic_map():
decoded = loads(unhexlify('d81ca100d81d00'))
assert decoded == {0: decoded}
def test_unhandled_tag():
"""
Test that a tag is simply ignored and its associated value returned if there is no special
handling available for it.
"""
decoded = loads(unhexlify('d917706548656c6c6f'))
assert decoded == CBORTag(6000, u'Hello')
def test_premature_end_of_stream():
"""
Test that the decoder detects a situation where read() returned fewer than expected bytes.
"""
exc = pytest.raises(CBORDecodeError, loads, unhexlify('437879'))
exc.match('premature end of stream \(expected to read 3 bytes, got 2 instead\)')
def test_tag_hook():
def reverse(decoder, tag, fp, shareable_index=None):
return tag.value[::-1]
decoded = loads(unhexlify('d917706548656c6c6f'), tag_hook=reverse)
assert decoded == u'olleH'
def test_tag_hook_cyclic():
class DummyType(object):
def __init__(self, value):
self.value = value
def unmarshal_dummy(decoder, tag, shareable_index=None):
instance = DummyType.__new__(DummyType)
decoder.set_shareable(shareable_index, instance)
instance.value = decoder.decode_from_bytes(tag.value)
return instance
decoded = loads(unhexlify('D81CD90BB849D81CD90BB843D81D00'), tag_hook=unmarshal_dummy)
assert isinstance(decoded, DummyType)
assert decoded.value.value is decoded
def test_object_hook():
class DummyType(object):
def __init__(self, state):
self.state = state
payload = unhexlify('A2616103616205')
decoded = loads(payload, object_hook=lambda decoder, value: DummyType(value))
assert isinstance(decoded, DummyType)
assert decoded.state == {'a': 3, 'b': 5}
def test_error_major_type():
exc = pytest.raises(CBORDecodeError, loads, b'')
assert str(exc.value).startswith('error reading major type at index 0: ')
def test_load_from_file(tmpdir):
path = tmpdir.join('testdata.cbor')
path.write_binary(b'\x82\x01\x0a')
with path.open('rb') as fp:
obj = load(fp)
assert obj == [1, 10]