branchmap: make "closed" a set from beginning instead of converting from list
Differential Revision: https://phab.mercurial-scm.org/D7427
from __future__ import absolute_import
import os
import sys
import unittest
# TODO migrate to canned cbor test strings and stop using thirdparty.cbor
tpp = os.path.normpath(
os.path.join(os.path.dirname(__file__), '..', 'mercurial', 'thirdparty')
)
if not os.path.exists(tpp):
# skip, not in a repo
sys.exit(80)
sys.path[0:0] = [tpp]
import cbor
del sys.path[0]
from mercurial.utils import cborutil
class TestCase(unittest.TestCase):
if not getattr(unittest.TestCase, 'assertRaisesRegex', False):
# Python 3.7 deprecates the regex*p* version, but 2.7 lacks
# the regex version.
assertRaisesRegex = ( # camelcase-required
unittest.TestCase.assertRaisesRegexp
)
def loadit(it):
return cbor.loads(b''.join(it))
class BytestringTests(TestCase):
def testsimple(self):
self.assertEqual(
list(cborutil.streamencode(b'foobar')), [b'\x46', b'foobar']
)
self.assertEqual(loadit(cborutil.streamencode(b'foobar')), b'foobar')
self.assertEqual(cborutil.decodeall(b'\x46foobar'), [b'foobar'])
self.assertEqual(
cborutil.decodeall(b'\x46foobar\x45fizbi'), [b'foobar', b'fizbi']
)
def testlong(self):
source = b'x' * 1048576
self.assertEqual(loadit(cborutil.streamencode(source)), source)
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
def testfromiter(self):
# This is the example from RFC 7049 Section 2.2.2.
source = [b'\xaa\xbb\xcc\xdd', b'\xee\xff\x99']
self.assertEqual(
list(cborutil.streamencodebytestringfromiter(source)),
[
b'\x5f',
b'\x44',
b'\xaa\xbb\xcc\xdd',
b'\x43',
b'\xee\xff\x99',
b'\xff',
],
)
self.assertEqual(
loadit(cborutil.streamencodebytestringfromiter(source)),
b''.join(source),
)
self.assertEqual(
cborutil.decodeall(
b'\x5f\x44\xaa\xbb\xcc\xdd' b'\x43\xee\xff\x99\xff'
),
[b'\xaa\xbb\xcc\xdd', b'\xee\xff\x99', b''],
)
for i, chunk in enumerate(
cborutil.decodeall(
b'\x5f\x44\xaa\xbb\xcc\xdd' b'\x43\xee\xff\x99\xff'
)
):
self.assertIsInstance(chunk, cborutil.bytestringchunk)
if i == 0:
self.assertTrue(chunk.isfirst)
else:
self.assertFalse(chunk.isfirst)
if i == 2:
self.assertTrue(chunk.islast)
else:
self.assertFalse(chunk.islast)
def testfromiterlarge(self):
source = [b'a' * 16, b'b' * 128, b'c' * 1024, b'd' * 1048576]
self.assertEqual(
loadit(cborutil.streamencodebytestringfromiter(source)),
b''.join(source),
)
def testindefinite(self):
source = b'\x00\x01\x02\x03' + b'\xff' * 16384
it = cborutil.streamencodeindefinitebytestring(source, chunksize=2)
self.assertEqual(next(it), b'\x5f')
self.assertEqual(next(it), b'\x42')
self.assertEqual(next(it), b'\x00\x01')
self.assertEqual(next(it), b'\x42')
self.assertEqual(next(it), b'\x02\x03')
self.assertEqual(next(it), b'\x42')
self.assertEqual(next(it), b'\xff\xff')
dest = b''.join(
cborutil.streamencodeindefinitebytestring(source, chunksize=42)
)
self.assertEqual(cbor.loads(dest), source)
self.assertEqual(b''.join(cborutil.decodeall(dest)), source)
for chunk in cborutil.decodeall(dest):
self.assertIsInstance(chunk, cborutil.bytestringchunk)
self.assertIn(len(chunk), (0, 8, 42))
encoded = b'\x5f\xff'
b = cborutil.decodeall(encoded)
self.assertEqual(b, [b''])
self.assertTrue(b[0].isfirst)
self.assertTrue(b[0].islast)
def testdecodevariouslengths(self):
for i in (0, 1, 22, 23, 24, 25, 254, 255, 256, 65534, 65535, 65536):
source = b'x' * i
encoded = b''.join(cborutil.streamencode(source))
if len(source) < 24:
hlen = 1
elif len(source) < 256:
hlen = 2
elif len(source) < 65536:
hlen = 3
elif len(source) < 1048576:
hlen = 5
self.assertEqual(
cborutil.decodeitem(encoded),
(True, source, hlen + len(source), cborutil.SPECIAL_NONE),
)
def testpartialdecode(self):
encoded = b''.join(cborutil.streamencode(b'foobar'))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -6, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -5, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:7]),
(True, b'foobar', 7, cborutil.SPECIAL_NONE),
)
def testpartialdecodevariouslengths(self):
lens = [
2,
3,
10,
23,
24,
25,
31,
100,
254,
255,
256,
257,
16384,
65534,
65535,
65536,
65537,
131071,
131072,
131073,
1048575,
1048576,
1048577,
]
for size in lens:
if size < 24:
hlen = 1
elif size < 2 ** 8:
hlen = 2
elif size < 2 ** 16:
hlen = 3
elif size < 2 ** 32:
hlen = 5
else:
assert False
source = b'x' * size
encoded = b''.join(cborutil.streamencode(source))
res = cborutil.decodeitem(encoded[0:1])
if hlen > 1:
self.assertEqual(
res, (False, None, -(hlen - 1), cborutil.SPECIAL_NONE)
)
else:
self.assertEqual(
res,
(False, None, -(size + hlen - 1), cborutil.SPECIAL_NONE),
)
# Decoding partial header reports remaining header size.
for i in range(hlen - 1):
self.assertEqual(
cborutil.decodeitem(encoded[0 : i + 1]),
(False, None, -(hlen - i - 1), cborutil.SPECIAL_NONE),
)
# Decoding complete header reports item size.
self.assertEqual(
cborutil.decodeitem(encoded[0:hlen]),
(False, None, -size, cborutil.SPECIAL_NONE),
)
# Decoding single byte after header reports item size - 1
self.assertEqual(
cborutil.decodeitem(encoded[0 : hlen + 1]),
(False, None, -(size - 1), cborutil.SPECIAL_NONE),
)
# Decoding all but the last byte reports -1 needed.
self.assertEqual(
cborutil.decodeitem(encoded[0 : hlen + size - 1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
# Decoding last byte retrieves value.
self.assertEqual(
cborutil.decodeitem(encoded[0 : hlen + size]),
(True, source, hlen + size, cborutil.SPECIAL_NONE),
)
def testindefinitepartialdecode(self):
encoded = b''.join(
cborutil.streamencodebytestringfromiter([b'foobar', b'biz'])
)
# First item should be begin of bytestring special.
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(True, None, 1, cborutil.SPECIAL_START_INDEFINITE_BYTESTRING),
)
# Second item should be the first chunk. But only available when
# we give it 7 bytes (1 byte header + 6 byte chunk).
self.assertEqual(
cborutil.decodeitem(encoded[1:2]),
(False, None, -6, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:3]),
(False, None, -5, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:4]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:5]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:6]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:7]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[1:8]),
(True, b'foobar', 7, cborutil.SPECIAL_NONE),
)
# Third item should be second chunk. But only available when
# we give it 4 bytes (1 byte header + 3 byte chunk).
self.assertEqual(
cborutil.decodeitem(encoded[8:9]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[8:10]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[8:11]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[8:12]),
(True, b'biz', 4, cborutil.SPECIAL_NONE),
)
# Fourth item should be end of indefinite stream marker.
self.assertEqual(
cborutil.decodeitem(encoded[12:13]),
(True, None, 1, cborutil.SPECIAL_INDEFINITE_BREAK),
)
# Now test the behavior when going through the decoder.
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:1]), (False, 1, 0)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:2]), (False, 1, 6)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:3]), (False, 1, 5)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:4]), (False, 1, 4)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:5]), (False, 1, 3)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:6]), (False, 1, 2)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:7]), (False, 1, 1)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:8]), (True, 8, 0)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:9]), (True, 8, 3)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:10]), (True, 8, 2)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:11]), (True, 8, 1)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:12]), (True, 12, 0)
)
self.assertEqual(
cborutil.sansiodecoder().decode(encoded[0:13]), (True, 13, 0)
)
decoder = cborutil.sansiodecoder()
decoder.decode(encoded[0:8])
values = decoder.getavailable()
self.assertEqual(values, [b'foobar'])
self.assertTrue(values[0].isfirst)
self.assertFalse(values[0].islast)
self.assertEqual(decoder.decode(encoded[8:12]), (True, 4, 0))
values = decoder.getavailable()
self.assertEqual(values, [b'biz'])
self.assertFalse(values[0].isfirst)
self.assertFalse(values[0].islast)
self.assertEqual(decoder.decode(encoded[12:]), (True, 1, 0))
values = decoder.getavailable()
self.assertEqual(values, [b''])
self.assertFalse(values[0].isfirst)
self.assertTrue(values[0].islast)
class StringTests(TestCase):
def testdecodeforbidden(self):
encoded = b'\x63foo'
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'string major type not supported'
):
cborutil.decodeall(encoded)
class IntTests(TestCase):
def testsmall(self):
self.assertEqual(list(cborutil.streamencode(0)), [b'\x00'])
self.assertEqual(cborutil.decodeall(b'\x00'), [0])
self.assertEqual(list(cborutil.streamencode(1)), [b'\x01'])
self.assertEqual(cborutil.decodeall(b'\x01'), [1])
self.assertEqual(list(cborutil.streamencode(2)), [b'\x02'])
self.assertEqual(cborutil.decodeall(b'\x02'), [2])
self.assertEqual(list(cborutil.streamencode(3)), [b'\x03'])
self.assertEqual(cborutil.decodeall(b'\x03'), [3])
self.assertEqual(list(cborutil.streamencode(4)), [b'\x04'])
self.assertEqual(cborutil.decodeall(b'\x04'), [4])
# Multiple value decode works.
self.assertEqual(
cborutil.decodeall(b'\x00\x01\x02\x03\x04'), [0, 1, 2, 3, 4]
)
def testnegativesmall(self):
self.assertEqual(list(cborutil.streamencode(-1)), [b'\x20'])
self.assertEqual(cborutil.decodeall(b'\x20'), [-1])
self.assertEqual(list(cborutil.streamencode(-2)), [b'\x21'])
self.assertEqual(cborutil.decodeall(b'\x21'), [-2])
self.assertEqual(list(cborutil.streamencode(-3)), [b'\x22'])
self.assertEqual(cborutil.decodeall(b'\x22'), [-3])
self.assertEqual(list(cborutil.streamencode(-4)), [b'\x23'])
self.assertEqual(cborutil.decodeall(b'\x23'), [-4])
self.assertEqual(list(cborutil.streamencode(-5)), [b'\x24'])
self.assertEqual(cborutil.decodeall(b'\x24'), [-5])
# Multiple value decode works.
self.assertEqual(
cborutil.decodeall(b'\x20\x21\x22\x23\x24'), [-1, -2, -3, -4, -5]
)
def testrange(self):
for i in range(-70000, 70000, 10):
encoded = b''.join(cborutil.streamencode(i))
self.assertEqual(encoded, cbor.dumps(i))
self.assertEqual(cborutil.decodeall(encoded), [i])
def testdecodepartialubyte(self):
encoded = b''.join(cborutil.streamencode(250))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 250, 2, cborutil.SPECIAL_NONE),
)
def testdecodepartialbyte(self):
encoded = b''.join(cborutil.streamencode(-42))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, -42, 2, cborutil.SPECIAL_NONE),
)
def testdecodepartialushort(self):
encoded = b''.join(cborutil.streamencode(2 ** 15))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, 2 ** 15, 3, cborutil.SPECIAL_NONE),
)
def testdecodepartialshort(self):
encoded = b''.join(cborutil.streamencode(-1024))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(True, -1024, 3, cborutil.SPECIAL_NONE),
)
def testdecodepartialulong(self):
encoded = b''.join(cborutil.streamencode(2 ** 28))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, 2 ** 28, 5, cborutil.SPECIAL_NONE),
)
def testdecodepartiallong(self):
encoded = b''.join(cborutil.streamencode(-1048580))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, -1048580, 5, cborutil.SPECIAL_NONE),
)
def testdecodepartialulonglong(self):
encoded = b''.join(cborutil.streamencode(2 ** 32))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -8, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -7, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -6, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -5, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:7]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:8]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:9]),
(True, 2 ** 32, 9, cborutil.SPECIAL_NONE),
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'input data not fully consumed'
):
cborutil.decodeall(encoded[0:1])
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'input data not fully consumed'
):
cborutil.decodeall(encoded[0:2])
def testdecodepartiallonglong(self):
encoded = b''.join(cborutil.streamencode(-7000000000))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -8, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -7, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -6, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -5, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:7]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:8]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:9]),
(True, -7000000000, 9, cborutil.SPECIAL_NONE),
)
class ArrayTests(TestCase):
def testempty(self):
self.assertEqual(list(cborutil.streamencode([])), [b'\x80'])
self.assertEqual(loadit(cborutil.streamencode([])), [])
self.assertEqual(cborutil.decodeall(b'\x80'), [[]])
def testbasic(self):
source = [b'foo', b'bar', 1, -10]
chunks = [b'\x84', b'\x43', b'foo', b'\x43', b'bar', b'\x01', b'\x29']
self.assertEqual(list(cborutil.streamencode(source)), chunks)
self.assertEqual(cborutil.decodeall(b''.join(chunks)), [source])
def testemptyfromiter(self):
self.assertEqual(
b''.join(cborutil.streamencodearrayfromiter([])), b'\x9f\xff'
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'indefinite length uint not allowed'
):
cborutil.decodeall(b'\x9f\xff')
def testfromiter1(self):
source = [b'foo']
self.assertEqual(
list(cborutil.streamencodearrayfromiter(source)),
[b'\x9f', b'\x43', b'foo', b'\xff',],
)
dest = b''.join(cborutil.streamencodearrayfromiter(source))
self.assertEqual(cbor.loads(dest), source)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'indefinite length uint not allowed'
):
cborutil.decodeall(dest)
def testtuple(self):
source = (b'foo', None, 42)
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cbor.loads(encoded), list(source))
self.assertEqual(cborutil.decodeall(encoded), [list(source)])
def testpartialdecode(self):
source = list(range(4))
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(True, 4, 1, cborutil.SPECIAL_START_ARRAY),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 4, 1, cborutil.SPECIAL_START_ARRAY),
)
source = list(range(23))
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(True, 23, 1, cborutil.SPECIAL_START_ARRAY),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 23, 1, cborutil.SPECIAL_START_ARRAY),
)
source = list(range(24))
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 24, 2, cborutil.SPECIAL_START_ARRAY),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(True, 24, 2, cborutil.SPECIAL_START_ARRAY),
)
source = list(range(256))
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(True, 256, 3, cborutil.SPECIAL_START_ARRAY),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(True, 256, 3, cborutil.SPECIAL_START_ARRAY),
)
def testnested(self):
source = [[], [], [[], [], []]]
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
source = [True, None, [True, 0, 2], [None], [], [[[]], -87]]
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
# A set within an array.
source = [None, {b'foo', b'bar', None, False}, set()]
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
# A map within an array.
source = [None, {}, {b'foo': b'bar', True: False}, [{}]]
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
def testindefinitebytestringvalues(self):
# Single value array whose value is an empty indefinite bytestring.
encoded = b'\x81\x5f\x40\xff'
with self.assertRaisesRegex(
cborutil.CBORDecodeError,
'indefinite length bytestrings not ' 'allowed as array values',
):
cborutil.decodeall(encoded)
class SetTests(TestCase):
def testempty(self):
self.assertEqual(
list(cborutil.streamencode(set())), [b'\xd9\x01\x02', b'\x80',]
)
self.assertEqual(cborutil.decodeall(b'\xd9\x01\x02\x80'), [set()])
def testset(self):
source = {b'foo', None, 42}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cbor.loads(encoded), source)
self.assertEqual(cborutil.decodeall(encoded), [source])
def testinvalidtag(self):
# Must use array to encode sets.
encoded = b'\xd9\x01\x02\xa0'
with self.assertRaisesRegex(
cborutil.CBORDecodeError,
'expected array after finite set ' 'semantic tag',
):
cborutil.decodeall(encoded)
def testpartialdecode(self):
# Semantic tag item will be 3 bytes. Set header will be variable
# depending on length.
encoded = b''.join(cborutil.streamencode({i for i in range(23)}))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(True, 23, 4, cborutil.SPECIAL_START_SET),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, 23, 4, cborutil.SPECIAL_START_SET),
)
encoded = b''.join(cborutil.streamencode({i for i in range(24)}))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, 24, 5, cborutil.SPECIAL_START_SET),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(True, 24, 5, cborutil.SPECIAL_START_SET),
)
encoded = b''.join(cborutil.streamencode({i for i in range(256)}))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(True, 256, 6, cborutil.SPECIAL_START_SET),
)
def testinvalidvalue(self):
encoded = b''.join(
[
b'\xd9\x01\x02', # semantic tag
b'\x81', # array of size 1
b'\x5f\x43foo\xff', # indefinite length bytestring "foo"
]
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError,
'indefinite length bytestrings not ' 'allowed as set values',
):
cborutil.decodeall(encoded)
encoded = b''.join([b'\xd9\x01\x02', b'\x81', b'\x80',]) # empty array
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'collections not allowed as set values'
):
cborutil.decodeall(encoded)
encoded = b''.join([b'\xd9\x01\x02', b'\x81', b'\xa0',]) # empty map
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'collections not allowed as set values'
):
cborutil.decodeall(encoded)
encoded = b''.join(
[
b'\xd9\x01\x02',
b'\x81',
b'\xd9\x01\x02\x81\x01', # set with integer 1
]
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'collections not allowed as set values'
):
cborutil.decodeall(encoded)
class BoolTests(TestCase):
def testbasic(self):
self.assertEqual(list(cborutil.streamencode(True)), [b'\xf5'])
self.assertEqual(list(cborutil.streamencode(False)), [b'\xf4'])
self.assertIs(loadit(cborutil.streamencode(True)), True)
self.assertIs(loadit(cborutil.streamencode(False)), False)
self.assertEqual(cborutil.decodeall(b'\xf4'), [False])
self.assertEqual(cborutil.decodeall(b'\xf5'), [True])
self.assertEqual(
cborutil.decodeall(b'\xf4\xf5\xf5\xf4'), [False, True, True, False]
)
class NoneTests(TestCase):
def testbasic(self):
self.assertEqual(list(cborutil.streamencode(None)), [b'\xf6'])
self.assertIs(loadit(cborutil.streamencode(None)), None)
self.assertEqual(cborutil.decodeall(b'\xf6'), [None])
self.assertEqual(cborutil.decodeall(b'\xf6\xf6'), [None, None])
class MapTests(TestCase):
def testempty(self):
self.assertEqual(list(cborutil.streamencode({})), [b'\xa0'])
self.assertEqual(loadit(cborutil.streamencode({})), {})
self.assertEqual(cborutil.decodeall(b'\xa0'), [{}])
def testemptyindefinite(self):
self.assertEqual(
list(cborutil.streamencodemapfromiter([])), [b'\xbf', b'\xff']
)
self.assertEqual(loadit(cborutil.streamencodemapfromiter([])), {})
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'indefinite length uint not allowed'
):
cborutil.decodeall(b'\xbf\xff')
def testone(self):
source = {b'foo': b'bar'}
self.assertEqual(
list(cborutil.streamencode(source)),
[b'\xa1', b'\x43', b'foo', b'\x43', b'bar'],
)
self.assertEqual(loadit(cborutil.streamencode(source)), source)
self.assertEqual(cborutil.decodeall(b'\xa1\x43foo\x43bar'), [source])
def testmultiple(self):
source = {
b'foo': b'bar',
b'baz': b'value1',
}
self.assertEqual(loadit(cborutil.streamencode(source)), source)
self.assertEqual(
loadit(cborutil.streamencodemapfromiter(source.items())), source
)
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
def testcomplex(self):
source = {
b'key': 1,
2: -10,
}
self.assertEqual(loadit(cborutil.streamencode(source)), source)
self.assertEqual(
loadit(cborutil.streamencodemapfromiter(source.items())), source
)
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
def testnested(self):
source = {b'key1': None, b'key2': {b'sub1': b'sub2'}, b'sub2': {}}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
source = {
b'key1': [],
b'key2': [None, False],
b'key3': {b'foo', b'bar'},
b'key4': {},
}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(cborutil.decodeall(encoded), [source])
def testillegalkey(self):
encoded = b''.join(
[
# map header + len 1
b'\xa1',
# indefinite length bytestring "foo" in key position
b'\x5f\x03foo\xff',
]
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError,
'indefinite length bytestrings not ' 'allowed as map keys',
):
cborutil.decodeall(encoded)
encoded = b''.join([b'\xa1', b'\x80', b'\x43foo',]) # empty array
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'collections not supported as map keys'
):
cborutil.decodeall(encoded)
def testillegalvalue(self):
encoded = b''.join(
[
b'\xa1', # map headers
b'\x43foo', # key
b'\x5f\x03bar\xff', # indefinite length value
]
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError,
'indefinite length bytestrings not ' 'allowed as map values',
):
cborutil.decodeall(encoded)
def testpartialdecode(self):
source = {b'key1': b'value1'}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(True, 1, 1, cborutil.SPECIAL_START_MAP),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 1, 1, cborutil.SPECIAL_START_MAP),
)
source = {b'key%d' % i: None for i in range(23)}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(True, 23, 1, cborutil.SPECIAL_START_MAP),
)
source = {b'key%d' % i: None for i in range(24)}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(True, 24, 2, cborutil.SPECIAL_START_MAP),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(True, 24, 2, cborutil.SPECIAL_START_MAP),
)
source = {b'key%d' % i: None for i in range(256)}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(True, 256, 3, cborutil.SPECIAL_START_MAP),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(True, 256, 3, cborutil.SPECIAL_START_MAP),
)
source = {b'key%d' % i: None for i in range(65536)}
encoded = b''.join(cborutil.streamencode(source))
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -4, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -3, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:3]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:4]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:5]),
(True, 65536, 5, cborutil.SPECIAL_START_MAP),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:6]),
(True, 65536, 5, cborutil.SPECIAL_START_MAP),
)
class SemanticTagTests(TestCase):
def testdecodeforbidden(self):
for i in range(500):
if i == cborutil.SEMANTIC_TAG_FINITE_SET:
continue
tag = cborutil.encodelength(cborutil.MAJOR_TYPE_SEMANTIC, i)
encoded = tag + cborutil.encodelength(cborutil.MAJOR_TYPE_UINT, 42)
# Partial decode is incomplete.
if i < 24:
pass
elif i < 256:
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
elif i < 65536:
self.assertEqual(
cborutil.decodeitem(encoded[0:1]),
(False, None, -2, cborutil.SPECIAL_NONE),
)
self.assertEqual(
cborutil.decodeitem(encoded[0:2]),
(False, None, -1, cborutil.SPECIAL_NONE),
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, r'semantic tag \d+ not allowed'
):
cborutil.decodeitem(encoded)
class SpecialTypesTests(TestCase):
def testforbiddentypes(self):
for i in range(256):
if i == cborutil.SUBTYPE_FALSE:
continue
elif i == cborutil.SUBTYPE_TRUE:
continue
elif i == cborutil.SUBTYPE_NULL:
continue
encoded = cborutil.encodelength(cborutil.MAJOR_TYPE_SPECIAL, i)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, r'special type \d+ not allowed'
):
cborutil.decodeitem(encoded)
class SansIODecoderTests(TestCase):
def testemptyinput(self):
decoder = cborutil.sansiodecoder()
self.assertEqual(decoder.decode(b''), (False, 0, 0))
class BufferingDecoderTests(TestCase):
def testsimple(self):
source = [
b'foobar',
b'x' * 128,
{b'foo': b'bar'},
True,
False,
None,
[None for i in range(128)],
]
encoded = b''.join(cborutil.streamencode(source))
for step in range(1, 32):
decoder = cborutil.bufferingdecoder()
start = 0
while start < len(encoded):
decoder.decode(encoded[start : start + step])
start += step
self.assertEqual(decoder.getavailable(), [source])
def testbytearray(self):
source = b''.join(cborutil.streamencode(b'foobar'))
decoder = cborutil.bufferingdecoder()
decoder.decode(bytearray(source))
self.assertEqual(decoder.getavailable(), [b'foobar'])
class DecodeallTests(TestCase):
def testemptyinput(self):
self.assertEqual(cborutil.decodeall(b''), [])
def testpartialinput(self):
encoded = b''.join(
[b'\x82', b'\x01',] # array of 2 elements # integer 1
)
with self.assertRaisesRegex(
cborutil.CBORDecodeError, 'input data not complete'
):
cborutil.decodeall(encoded)
if __name__ == '__main__':
import silenttestrunner
silenttestrunner.main(__name__)