From 02be0f57f2088341ebc245c103935d5445f57013 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Tue, 21 Sep 2010 20:34:55 -0500 Subject: [PATCH] Add vint tests and signed vint support via write_vint and read_vint. Signed-off-by: Rob Browning --- lib/bup/t/tvint.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++ lib/bup/vint.py | 53 +++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/bup/t/tvint.py diff --git a/lib/bup/t/tvint.py b/lib/bup/t/tvint.py new file mode 100644 index 0000000..1be4c42 --- /dev/null +++ b/lib/bup/t/tvint.py @@ -0,0 +1,85 @@ +from bup import vint +from wvtest import * +from cStringIO import StringIO + + +def encode_and_decode_vuint(x): + f = StringIO() + vint.write_vuint(f, x) + return vint.read_vuint(StringIO(f.getvalue())) + + +@wvtest +def test_vuint(): + for x in (0, 1, 42, 128, 10**16): + WVPASSEQ(encode_and_decode_vuint(x), x) + WVEXCEPT(Exception, vint.write_vuint, StringIO(), -1) + WVEXCEPT(EOFError, vint.read_vuint, StringIO()) + + +def encode_and_decode_vint(x): + f = StringIO() + vint.write_vint(f, x) + return vint.read_vint(StringIO(f.getvalue())) + + +@wvtest +def test_vint(): + values = (0, 1, 42, 64, 10**16) + for x in values: + WVPASSEQ(encode_and_decode_vint(x), x) + for x in [-x for x in values]: + WVPASSEQ(encode_and_decode_vint(x), x) + WVEXCEPT(EOFError, vint.read_vint, StringIO()) + + +def encode_and_decode_bvec(x): + f = StringIO() + vint.write_bvec(f, x) + return vint.read_bvec(StringIO(f.getvalue())) + + +@wvtest +def test_bvec(): + values = ('', 'x', 'foo', '\0', '\0foo', 'foo\0bar\0') + for x in values: + WVPASSEQ(encode_and_decode_bvec(x), x) + WVEXCEPT(EOFError, vint.read_bvec, StringIO()) + outf = StringIO() + for x in ('foo', 'bar', 'baz', 'bax'): + vint.write_bvec(outf, x) + inf = StringIO(outf.getvalue()) + WVPASSEQ(vint.read_bvec(inf), 'foo') + WVPASSEQ(vint.read_bvec(inf), 'bar') + vint.skip_bvec(inf) + WVPASSEQ(vint.read_bvec(inf), 'bax') + + +def pack_and_unpack(types, *values): + data = vint.pack(types, *values) + return vint.unpack(types, data) + + +@wvtest +def test_pack_and_unpack(): + tests = [('', []), + ('s', ['foo']), + ('ss', ['foo', 'bar']), + ('sV', ['foo', 0]), + ('sv', ['foo', -1]), + ('V', [0]), + ('Vs', [0, 'foo']), + ('VV', [0, 1]), + ('Vv', [0, -1]), + ('v', [0]), + ('vs', [0, 'foo']), + ('vV', [0, 1]), + ('vv', [0, -1])] + for test in tests: + (types, values) = test + WVPASSEQ(pack_and_unpack(types, *values), values) + WVEXCEPT(Exception, vint.pack, 's') + WVEXCEPT(Exception, vint.pack, 's', 'foo', 'bar') + WVEXCEPT(Exception, vint.pack, 'x', 1) + WVEXCEPT(Exception, vint.unpack, 's', '') + WVEXCEPT(Exception, vint.unpack, 'x', '') diff --git a/lib/bup/vint.py b/lib/bup/vint.py index 31e2dfa..8f7f58a 100644 --- a/lib/bup/vint.py +++ b/lib/bup/vint.py @@ -42,6 +42,55 @@ def read_vuint(port): return result +def write_vint(port, x): + # Sign is handled with the second bit of the first byte. All else + # matches vuint. + if x == 0: + port.write('\0') + else: + if x < 0: + x = -x + sign_and_six_bits = (x & 0x3f) | 0x40 + else: + sign_and_six_bits = x & 0x3f + x >>= 6 + if x: + port.write(chr(0x80 | sign_and_six_bits)) + write_vuint(port, x) + else: + port.write(chr(sign_and_six_bits)) + + +def read_vint(port): + c = port.read(1) + if c == '': + raise EOFError('encountered EOF while reading vint'); + negative = False + result = 0 + offset = 0 + # Handle first byte with sign bit specially. + if c: + b = ord(c) + if b & 0x40: + negative = True + result |= (b & 0x3f) + if b & 0x80: + offset += 6 + c = port.read(1) + else: + return -result if negative else result + while c: + b = ord(c) + if b & 0x80: + result |= ((b & 0x7f) << offset) + offset += 7 + c = port.read(1) + else: + result |= (b << offset) + break + return -result if negative else result + + def write_bvec(port, x): write_vuint(port, len(x)) port.write(x) @@ -63,6 +112,8 @@ def pack(types, *args): for (type, value) in zip(types, args): if type == 'V': write_vuint(port, value) + elif type == 'v': + write_vint(port, value) elif type == 's': write_bvec(port, value) else: @@ -76,6 +127,8 @@ def unpack(types, data): for type in types: if type == 'V': result.append(read_vuint(port)) + elif type == 'v': + result.append(read_vint(port)) elif type == 's': result.append(read_bvec(port)) else: -- 2.39.2