blob: fcd17faaa373afa5d492e52f9923b1d57e21b671 [file] [log] [blame]
# Lint as: python3
# Copyright 2020 Google Inc. All rights reserved.
#
# 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.
"""Unit tests for flexbuffers.py."""
import array
import os.path
import struct
import unittest
from flatbuffers import flexbuffers
Type = flexbuffers.Type
LOG2 = {1: 0, 2: 1, 4: 2, 8: 3}
GOLD_FLEXBUFFER_OBJ = {
'bar': [1, 2, 3],
'bar3': [1, 2, 3],
'bool': True,
'bools': [True, False, True, False],
'foo': 100.0,
'mymap': {'foo': 'Fred'},
'vec': [-100, 'Fred', 4.0, b'M', False, 4.0]
}
GOLD_FLEXBUFFER_FILE = 'gold_flexbuffer_example.bin'
def read_test_file(name):
with open(os.path.join(os.path.dirname(__file__), name), 'rb') as f:
return f.read()
def packed_type(type_, i):
return (type_ << 2) | LOG2[i]
def uint_size(value):
"""Returns number of bytes (power of two) to represent unsigned value."""
assert value >= 0
n = 8
while not value < (1 << n):
n *= 2
return n // 8
def int_size(value):
"""Returns number of bytes (power of two) to represent signed value."""
n = 8
while not -(1 << (n - 1)) <= value < (1 << (n - 1)):
n *= 2
return n // 8
def uint_sizes(value):
return tuple(1 << i for i in range(LOG2[uint_size(value)], 4))
def int_sizes(value):
return tuple(1 << i for i in range(LOG2[int_size(value)], 4))
def int_bytes(value, byte_width):
return struct.pack('<%s' % {1: 'b', 2: 'h', 4: 'i', 8: 'q'}[byte_width], value)
def uint_bytes(value, byte_width):
return struct.pack('<%s' % {1: 'B', 2: 'H', 4: 'I', 8: 'Q'}[byte_width], value)
def float_bytes(value, byte_width):
return struct.pack('<%s' % {4: 'f', 8: 'd'}[byte_width], value)
def min_value(type_, byte_width):
assert byte_width > 0
if type_ in (Type.INT, Type.INDIRECT_INT):
return -(1 << (8 * byte_width - 1))
elif type_ in (Type.UINT, Type.INDIRECT_UINT):
return 0
else:
raise ValueError('Unsupported type %s' % type_)
def max_value(type_, byte_width):
assert byte_width > 0
if type_ in (Type.INT, Type.INDIRECT_INT):
return (1 << (8 * byte_width - 1)) - 1
elif type_ in (Type.UINT, Type.INDIRECT_UINT):
return (1 << 8 * byte_width) - 1
else:
raise ValueError('Unsupported type %s' % type_)
def str_bytes(value, byte_width):
value_bytes = value.encode('utf-8')
return [*uint_bytes(len(value_bytes), byte_width), *value_bytes, 0]
def key_bytes(value):
return [*value.encode('ascii'), 0]
def encode_type(type_, value, byte_width=None):
fbb = flexbuffers.Builder()
add = fbb.Adder(type_)
if byte_width:
add(value, byte_width)
else:
add(value)
return fbb.Finish()
INT_MIN_MAX_VALUES = (min_value(Type.INT, 1), max_value(Type.INT, 1),
min_value(Type.INT, 2), max_value(Type.INT, 2),
min_value(Type.INT, 4), max_value(Type.INT, 4),
min_value(Type.INT, 8), max_value(Type.INT, 8))
UINT_MIN_MAX_VALUES = (0, max_value(Type.UINT, 1), max_value(Type.UINT, 2),
max_value(Type.UINT, 4), max_value(Type.UINT, 8))
class UtilTest(unittest.TestCase):
"""Tests to check FlexBuffer utility functions."""
def _test_type_predicate(self, pred, types):
for type_ in types:
with self.subTest(type=type_, pred=pred):
self.assertTrue(pred(type_))
for type_ in set(Type).difference(types):
with self.subTest(type=type_, pred=pred):
self.assertFalse(pred(type_))
def test_inline_types(self):
self._test_type_predicate(
Type.IsInline, (Type.NULL, Type.INT, Type.UINT, Type.FLOAT, Type.BOOL))
def test_typed_vector(self):
self._test_type_predicate(
Type.IsTypedVector,
(Type.VECTOR_INT, Type.VECTOR_UINT, Type.VECTOR_FLOAT, Type.VECTOR_KEY,
Type.VECTOR_STRING_DEPRECATED, Type.VECTOR_BOOL))
self._test_type_predicate(
Type.IsTypedVectorElementType,
(Type.INT, Type.UINT, Type.FLOAT, Type.KEY, Type.STRING, Type.BOOL))
with self.assertRaises(ValueError):
Type.ToTypedVectorElementType(Type.VECTOR)
self.assertIs(Type.ToTypedVectorElementType(Type.VECTOR_INT), Type.INT)
self.assertIs(Type.ToTypedVectorElementType(Type.VECTOR_UINT), Type.UINT)
self.assertIs(Type.ToTypedVectorElementType(Type.VECTOR_FLOAT), Type.FLOAT)
self.assertIs(Type.ToTypedVectorElementType(Type.VECTOR_KEY), Type.KEY)
self.assertIs(
Type.ToTypedVectorElementType(Type.VECTOR_STRING_DEPRECATED),
Type.STRING)
self.assertIs(Type.ToTypedVectorElementType(Type.VECTOR_BOOL), Type.BOOL)
with self.assertRaises(ValueError):
Type.ToTypedVector(Type.VECTOR)
self.assertIs(Type.ToTypedVector(Type.INT), Type.VECTOR_INT)
self.assertIs(Type.ToTypedVector(Type.UINT), Type.VECTOR_UINT)
self.assertIs(Type.ToTypedVector(Type.FLOAT), Type.VECTOR_FLOAT)
self.assertIs(Type.ToTypedVector(Type.KEY), Type.VECTOR_KEY)
self.assertIs(
Type.ToTypedVector(Type.STRING), Type.VECTOR_STRING_DEPRECATED)
self.assertIs(Type.ToTypedVector(Type.BOOL), Type.VECTOR_BOOL)
def test_fixed_typed_vector(self):
self._test_type_predicate(
Type.IsFixedTypedVector,
(Type.VECTOR_INT2, Type.VECTOR_UINT2, Type.VECTOR_FLOAT2,
Type.VECTOR_INT3, Type.VECTOR_UINT3, Type.VECTOR_FLOAT3,
Type.VECTOR_INT4, Type.VECTOR_UINT4, Type.VECTOR_FLOAT4))
self._test_type_predicate(Type.IsFixedTypedVectorElementType,
(Type.INT, Type.UINT, Type.FLOAT))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_INT2), (Type.INT, 2))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_UINT2), (Type.UINT, 2))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_FLOAT2), (Type.FLOAT, 2))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_INT3), (Type.INT, 3))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_UINT3), (Type.UINT, 3))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_FLOAT3), (Type.FLOAT, 3))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_INT4), (Type.INT, 4))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_UINT4), (Type.UINT, 4))
self.assertEqual(
Type.ToFixedTypedVectorElementType(Type.VECTOR_FLOAT4), (Type.FLOAT, 4))
# Invalid size
for type_ in Type.INT, Type.UINT, Type.FLOAT:
with self.assertRaises(ValueError):
Type.ToTypedVector(type_, 1)
with self.assertRaises(ValueError):
Type.ToTypedVector(type_, 5)
# Invalid element type
for length in 1, 2, 3, 4, 5:
with self.assertRaises(ValueError):
Type.ToTypedVector(Type.STRING, length)
self.assertIs(Type.ToTypedVector(Type.INT, 2), Type.VECTOR_INT2)
self.assertIs(Type.ToTypedVector(Type.INT, 3), Type.VECTOR_INT3)
self.assertIs(Type.ToTypedVector(Type.INT, 4), Type.VECTOR_INT4)
self.assertIs(Type.ToTypedVector(Type.UINT, 2), Type.VECTOR_UINT2)
self.assertIs(Type.ToTypedVector(Type.UINT, 3), Type.VECTOR_UINT3)
self.assertIs(Type.ToTypedVector(Type.UINT, 4), Type.VECTOR_UINT4)
self.assertIs(Type.ToTypedVector(Type.FLOAT, 2), Type.VECTOR_FLOAT2)
self.assertIs(Type.ToTypedVector(Type.FLOAT, 3), Type.VECTOR_FLOAT3)
self.assertIs(Type.ToTypedVector(Type.FLOAT, 4), Type.VECTOR_FLOAT4)
def test_width(self):
for x in range(1 << 10):
self.assertEqual(flexbuffers.BitWidth.U(x), LOG2[uint_size(x)])
for x in range(-(1 << 10), 1 << 10):
self.assertEqual(flexbuffers.BitWidth.I(x), LOG2[int_size(x)])
def test_padding(self):
self.assertEqual(flexbuffers._PaddingBytes(0, 4), 0)
self.assertEqual(flexbuffers._PaddingBytes(0, 8), 0)
self.assertEqual(flexbuffers._PaddingBytes(0, 16), 0)
self.assertEqual(flexbuffers._PaddingBytes(1, 8), 7)
self.assertEqual(flexbuffers._PaddingBytes(17, 8), 7)
self.assertEqual(flexbuffers._PaddingBytes(42, 2), 0)
class DecoderTest(unittest.TestCase):
"""Tests to check FlexBuffer decoding functions.
Common variable names used in the tests for compactness:
bw: byte_width
ebw: element_byte_width
kbw: key_byte_width
vbw: value_byte_width
tbw: type_byte_width
Having '_ignored' suffix means that variable doesn't affect the constructed
byte buffer size.
"""
def test_null(self):
for bw in 1, 2, 4, 8:
for ebw_ignored in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw_ignored=ebw_ignored):
data = bytes([
*uint_bytes(0, bw),
packed_type(Type.NULL, ebw_ignored),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsNull)
self.assertEqual(root.AsBool, False)
self.assertEqual(root.AsInt, 0)
self.assertEqual(root.AsFloat, 0.0)
for prop in (type(root).AsKey, type(root).AsString, type(root).AsBlob,
type(root).AsVector, type(root).AsTypedVector,
type(root).AsFixedTypedVector, type(root).AsMap):
with self.assertRaises(TypeError):
prop.fget(root)
self.assertEqual(root.Value, None)
self.assertIsNone(flexbuffers.Loads(data))
def test_bool(self):
for value in False, True:
for bw in 1, 2, 4, 8:
for ebw_ignored in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw_ignored=ebw_ignored):
data = bytes([
*uint_bytes(int(value), bw),
packed_type(Type.BOOL, ebw_ignored),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsBool)
self.assertEqual(root.AsBool, value)
self.assertEqual(root.AsInt, int(value))
self.assertEqual(root.AsFloat, float(value))
for prop in (type(root).AsKey, type(root).AsString,
type(root).AsBlob,
type(root).AsVector, type(root).AsTypedVector,
type(root).AsFixedTypedVector, type(root).AsMap):
with self.assertRaises(TypeError):
prop.fget(root)
self.assertEqual(root.Value, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_mutate_bool(self):
root = flexbuffers.GetRoot(flexbuffers.Dumps(True))
self.assertTrue(root.IsBool)
self.assertTrue(root.AsBool)
self.assertTrue(root.MutateBool(False))
self.assertTrue(root.IsBool)
self.assertFalse(root.AsBool)
self.assertTrue(root.MutateBool(True))
self.assertTrue(root.IsBool)
self.assertTrue(root.AsBool)
def _check_int(self, data, value):
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsInt)
self.assertEqual(root.AsInt, value)
self.assertEqual(root.AsBool, bool(value))
self.assertEqual(root.AsFloat, float(value))
for prop in (type(root).AsKey, type(root).AsString, type(root).AsBlob,
type(root).AsVector, type(root).AsTypedVector,
type(root).AsFixedTypedVector, type(root).AsMap):
with self.assertRaises(TypeError):
prop.fget(root)
self.assertEqual(root.Value, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_int(self):
for value in (0, 1, -1, 15, -17, *INT_MIN_MAX_VALUES):
for bw in int_sizes(value):
for ebw_ignored in 1, 2, 4, 8:
with self.subTest(value=value, bw=bw, ebw_ignored=ebw_ignored):
data = bytes([
*int_bytes(value, bw),
packed_type(Type.INT, ebw_ignored),
bw,
])
self._check_int(data, value)
def test_indirect_int(self):
for value in (0, 1, -1, 15, -17, *INT_MIN_MAX_VALUES):
for bw in 1, 2, 4, 8:
for ebw in int_sizes(value):
with self.subTest(value=value, bw=bw, ebw=ebw):
data = bytes([
# Int
*int_bytes(value, ebw),
# Root
*uint_bytes(ebw, bw),
packed_type(Type.INDIRECT_INT, ebw),
bw,
])
self._check_int(data, value)
def test_uint(self):
for value in (1, *UINT_MIN_MAX_VALUES):
for bw in uint_sizes(value):
for ebw_ignored in 1, 2, 4, 8:
with self.subTest(value=value, bw=bw, ebw_ignored=ebw_ignored):
data = bytes([
*uint_bytes(value, bw),
packed_type(Type.UINT, ebw_ignored),
bw,
])
self._check_int(data, value)
def test_inidirect_uint(self):
for value in (1, *UINT_MIN_MAX_VALUES):
for bw in 1, 2, 4, 8:
for ebw in uint_sizes(value):
with self.subTest(value=value, bw=bw, ebw=ebw):
data = bytes([
# UInt
*uint_bytes(value, ebw),
# Root
*uint_bytes(ebw, bw),
packed_type(Type.INDIRECT_UINT, ebw),
bw,
])
self._check_int(data, value)
def test_mutate_ints(self):
# Signed
for type_ in Type.INT, Type.INDIRECT_INT:
with self.subTest(type=type_):
root = flexbuffers.GetRoot(encode_type(type_, 56))
self.assertEqual(root.AsInt, 56)
for new_value in 0, 1, -1, -128, 127:
self.assertTrue(root.MutateInt(new_value))
self.assertEqual(root.AsInt, new_value)
for new_value in -129, 128:
self.assertFalse(root.MutateInt(new_value))
# Unsigned
for type_ in Type.UINT, Type.INDIRECT_UINT:
with self.subTest(type=type_):
root = flexbuffers.GetRoot(encode_type(type_, 1))
self.assertEqual(root.AsInt, 1)
for new_value in 0, 1, 255:
self.assertTrue(root.MutateInt(new_value))
self.assertEqual(root.AsInt, new_value)
self.assertFalse(root.MutateInt(256))
# Inside vector
fbb = flexbuffers.Builder()
fbb.VectorFromElements([13, 0, -15])
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), [13, 0, -15])
self.assertTrue(flexbuffers.GetRoot(data).AsVector[0].MutateInt(0))
self.assertTrue(flexbuffers.GetRoot(data).AsVector[1].MutateInt(-7))
self.assertTrue(flexbuffers.GetRoot(data).AsVector[2].MutateInt(45))
self.assertEqual(flexbuffers.Loads(data), [0, -7, 45])
# Inside map
fbb = flexbuffers.Builder()
fbb.MapFromElements({'x': -7, 'y': 46})
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), {'x': -7, 'y': 46})
self.assertTrue(flexbuffers.GetRoot(data).AsMap['x'].MutateInt(14))
self.assertTrue(flexbuffers.GetRoot(data).AsMap['y'].MutateInt(-1))
self.assertEqual(flexbuffers.Loads(data), {'x': 14, 'y': -1})
def _check_float(self, data, value):
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsFloat)
self.assertAlmostEqual(root.AsFloat, value)
for prop in (type(root).AsKey, type(root).AsString, type(root).AsBlob,
type(root).AsVector, type(root).AsTypedVector,
type(root).AsFixedTypedVector, type(root).AsMap):
with self.assertRaises(TypeError):
prop.fget(root)
self.assertAlmostEqual(root.Value, value)
self.assertAlmostEqual(flexbuffers.Loads(data), value)
def test_float(self):
for value in -1.0, 0.0, 1.0, 3.141592, 1.5e6:
for bw in 4, 8:
for ebw_ignored in 1, 2, 4, 8:
with self.subTest(value=value, bw=bw, ebw_ignored=ebw_ignored):
data = bytes([
*float_bytes(value, bw),
packed_type(Type.FLOAT, ebw_ignored),
bw,
])
self._check_float(data, value)
def test_indirect_float(self):
for value in -1.0, 0.0, 1.0, 3.141592, 1.5e6:
for bw in 1, 2, 4, 8:
for ebw in 4, 8:
with self.subTest(value=value, bw=bw, ebw=ebw):
data = bytes([
# Float
*float_bytes(value, ebw),
# Root
*uint_bytes(ebw, bw),
packed_type(Type.INDIRECT_FLOAT, ebw),
bw,
])
self._check_float(data, value)
def test_mutate_float(self):
for type_ in Type.FLOAT, Type.INDIRECT_FLOAT:
for bw in 4, 8:
value = 3.141592
root = flexbuffers.GetRoot(encode_type(type_, value, bw))
self.assertAlmostEqual(root.AsFloat, value)
value = 2.71828
self.assertTrue(root.MutateFloat(value))
self.assertAlmostEqual(root.AsFloat, value, places=5)
# Inside vector
data = flexbuffers.Dumps([2.4, 1.5, -7.2])
self.assertTrue(flexbuffers.GetRoot(data).AsVector[0].MutateFloat(0.0))
self.assertTrue(flexbuffers.GetRoot(data).AsVector[1].MutateFloat(15.2))
self.assertTrue(flexbuffers.GetRoot(data).AsVector[2].MutateFloat(-5.1))
for a, b in zip(flexbuffers.Loads(data), [0.0, 15.2, -5.1]):
self.assertAlmostEqual(a, b)
def test_string(self):
for value in 'red', 'green', 'blue', 'flatbuffers + flexbuffers':
value_bytes = value.encode('utf-8')
for bw in 1, 2, 4, 8:
for lbw in 1, 2, 4, 8:
with self.subTest(bw=bw, lbw=lbw):
data = bytes([
# String
*uint_bytes(len(value_bytes), lbw),
*value_bytes,
0,
# Root
*uint_bytes(len(value_bytes) + 1, bw), # offset
packed_type(Type.STRING, lbw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsString)
self.assertEqual(root.AsString, value)
self.assertEqual(root.Value, value)
self.assertEqual(root.AsInt, len(value))
self.assertEqual(flexbuffers.Loads(data), value)
def test_mutate_string(self):
data = encode_type(Type.STRING, '12345')
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsString)
self.assertEqual(root.AsString, '12345')
self.assertFalse(root.MutateString('543210'))
self.assertTrue(root.MutateString('54321'))
self.assertTrue(root.IsString)
self.assertEqual(root.AsString, '54321')
self.assertTrue(root.MutateString('543'))
self.assertTrue(root.IsString)
self.assertEqual(root.AsString, '543')
self.assertFalse(root.MutateString('54321'))
def test_empty_blob(self):
for bw in 1, 2, 4, 8:
for lbw in 1, 2, 4, 8:
with self.subTest(bw=bw, lbw=lbw):
data = bytes([
# Blob
*uint_bytes(0, lbw),
# Root
*uint_bytes(0, bw),
packed_type(Type.BLOB, lbw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsBlob)
self.assertEqual(root.AsBlob, bytes())
self.assertEqual(root.Value, bytes())
self.assertEqual(flexbuffers.Loads(data), bytes())
def test_blob(self):
for blob in [], [215], [23, 75, 124, 0, 45, 15], 255 * [0]:
for bw in 1, 2, 4, 8:
for lbw in 1, 2, 4, 8:
with self.subTest(blob=blob, bw=bw, lbw=lbw):
data = bytes([
# Blob
*uint_bytes(len(blob), lbw),
*blob,
# Root
*uint_bytes(len(blob), bw),
packed_type(Type.BLOB, lbw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsBlob)
self.assertEqual(root.AsBlob, bytes(blob))
self.assertEqual(root.Value, bytes(blob))
self.assertEqual(flexbuffers.Loads(data), bytes(blob))
def test_key(self):
for value in '', 'x', 'color':
for bw in 1, 2, 4, 8:
with self.subTest(value=value, bw=bw):
value_bytes = value.encode('ascii')
data = bytes([
# Key
*value_bytes,
0,
# Root
*uint_bytes(len(value_bytes) + 1, bw),
packed_type(Type.KEY, 1),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsKey)
self.assertEqual(root.AsKey, value)
self.assertEqual(root.Value, value)
self.assertEqual(flexbuffers.Loads(data), value)
def _check_fixed_typed_vector(self, data, vector, type_):
self.assertEqual(flexbuffers.Loads(data), vector)
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsFixedTypedVector)
v = root.AsFixedTypedVector
self.assertEqual(len(v), len(vector))
self.assertIs(v.ElementType, type_)
self.assertEqual([e.Value for e in v], vector)
self.assertSequenceEqual(v.Value, vector)
self.assertEqual(root.AsInt, len(vector))
def test_fixed_typed_vector_float(self):
for type_, vector in ((Type.VECTOR_FLOAT2, [-75.0, 34.89]),
(Type.VECTOR_FLOAT3, [-75.0, 34.89, 12.0]),
(Type.VECTOR_FLOAT4, [-75.0, 34.89, -1.0, 1.0])):
for bw in 1, 2, 4, 8:
for ebw in 4, 8:
with self.subTest(type=type_, vector=vector, bw=bw, ebw=ebw):
data = bytes([
# FixedTypedVector
*b''.join(float_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(len(vector) * ebw, bw),
packed_type(type_, ebw),
bw,
])
for a, b in zip(flexbuffers.Loads(data), vector):
self.assertAlmostEqual(a, b, places=2)
def test_fixed_typed_vector_int(self):
for type_, vector in ((Type.VECTOR_INT2, [0, -13]), (Type.VECTOR_INT3,
[127, 0, -13]),
(Type.VECTOR_INT4, [127, 0, -13, 0])):
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(type=type_, vector=vector, bw=bw, ebw=ebw):
data = bytes([
# FixedTypeVector
*b''.join(int_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(ebw * len(vector), bw),
packed_type(type_, ebw),
bw,
])
self._check_fixed_typed_vector(data, vector, Type.INT)
def test_fixed_typed_vector_uint(self):
for type_, vector in ((Type.VECTOR_UINT2, [0, 13]),
(Type.VECTOR_UINT3, [127, 0, 13]), (Type.VECTOR_UINT4,
[127, 0, 13, 0])):
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(type=type_, vector=vector, bw=bw, ebw=ebw):
data = bytes([
# FixedTypeVector
*b''.join(uint_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(ebw * len(vector), bw),
packed_type(type_, ebw),
bw,
])
self._check_fixed_typed_vector(data, vector, Type.UINT)
def _check_typed_vector(self, data, vector, type_):
self.assertEqual(flexbuffers.Loads(data), vector)
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsTypedVector)
v = root.AsTypedVector
self.assertIs(v.ElementType, type_)
self.assertEqual(len(v), len(vector))
self.assertEqual([e.Value for e in v], vector)
self.assertSequenceEqual(v.Value, vector)
self.assertEqual(root.AsInt, len(vector))
def test_empty_typed_vector(self):
for type_ in (Type.VECTOR_BOOL, Type.VECTOR_INT, Type.VECTOR_UINT,
Type.VECTOR_FLOAT, Type.VECTOR_KEY,
Type.VECTOR_STRING_DEPRECATED):
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(type=type_, bw=bw, ebw=ebw):
data = bytes([
# TypedVector[type_]
*uint_bytes(0, ebw),
# Root
*uint_bytes(0, bw),
packed_type(type_, ebw),
bw
])
element_type = Type.ToTypedVectorElementType(type_)
if element_type == Type.STRING:
element_type = Type.KEY
self._check_typed_vector(data, [], element_type)
def test_typed_vector_bool(self):
vector = [True, False, False, False, True]
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# TypedVector[Type.BOOL]
*uint_bytes(len(vector), ebw),
*b''.join(uint_bytes(int(e), ebw) for e in vector),
# Root
*uint_bytes(len(vector) * ebw, bw),
packed_type(Type.VECTOR_BOOL, ebw),
bw,
])
self._check_typed_vector(data, vector, Type.BOOL)
def test_typed_vector_int(self):
vector = [-100, 200, -300]
for bw in 1, 2, 4, 8:
for ebw in 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# TypedVector[Type.INT]
*uint_bytes(len(vector), ebw),
*b''.join(int_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(len(vector) * ebw, bw),
packed_type(Type.VECTOR_INT, ebw),
bw,
])
self._check_typed_vector(data, vector, Type.INT)
def test_typed_vector_uint(self):
vector = [100, 200, 300, 400, 0]
for bw in 1, 2, 4, 8:
for ebw in 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# TypedVector[Type.UINT]
*uint_bytes(len(vector), ebw),
*b''.join(int_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(len(vector) * ebw, bw),
packed_type(Type.VECTOR_UINT, ebw),
bw,
])
self._check_typed_vector(data, vector, Type.UINT)
def test_typed_vector_float(self):
vector = [3.64, -6.36, 3.14, 634.0, -42.0]
for bw in 1, 2, 4, 8:
for ebw in 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# TypedVector[Type.FLOAT]
*uint_bytes(len(vector), ebw),
*b''.join(float_bytes(e, ebw) for e in vector),
# Root
*uint_bytes(ebw * len(vector), bw),
packed_type(Type.VECTOR_FLOAT, ebw),
bw,
])
for a, b in zip(flexbuffers.Loads(data), vector):
self.assertAlmostEqual(a, b, places=2)
def test_typed_vector_key(self):
vector = ['red', 'green', 'blue']
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# Keys
*key_bytes(vector[0]),
*key_bytes(vector[1]),
*key_bytes(vector[2]),
# TypedVector[Type.KEY]
*uint_bytes(len(vector), ebw),
*uint_bytes(15 + 1 * ebw, ebw), # offset to vector[0]
*uint_bytes(11 + 2 * ebw, ebw), # offset to vector[1]
*uint_bytes(5 + 3 * ebw, ebw), # offset to vector[2]
# Root
*uint_bytes(len(vector) * ebw, bw), # offset to vector
packed_type(Type.VECTOR_KEY, ebw),
bw,
])
self._check_typed_vector(data, vector, Type.KEY)
def test_typed_vector_string(self):
vector = ['red', 'green', 'blue']
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw):
data = bytes([
# Strings
*str_bytes(vector[0], 1), # 5 bytes
*str_bytes(vector[1], 1), # 7 bytes
*str_bytes(vector[2], 1), # 6 bytes
# TypedVector[Type.STRING]
*uint_bytes(len(vector), ebw),
*uint_bytes(17 + 1 * ebw, ebw), # offset to vector[0]
*uint_bytes(12 + 2 * ebw, ebw), # offset to vector[1]
*uint_bytes(5 + 3 * ebw, ebw), # offset to vector[2]
# Root
*uint_bytes(len(vector) * ebw, bw), # offset to vector
packed_type(Type.VECTOR_STRING_DEPRECATED, ebw),
bw,
])
# We have to pass Type.KEY because of Type.VECTOR_STRING_DEPRECATED.
self._check_typed_vector(data, vector, Type.KEY)
def test_typed_vector_string_deprecated(self):
# Check FlexBuffersDeprecatedTest() inside test.cpp for details.
vector = [300 * 'A', 'test']
fbb = flexbuffers.Builder()
with fbb.TypedVector():
for e in vector:
fbb.String(e)
data = fbb.Finish()
# We have to pass Type.KEY because of Type.VECTOR_STRING_DEPRECATED.
self._check_typed_vector(data, vector, Type.KEY)
def test_typed_vector_invalid(self):
fbb = flexbuffers.Builder()
with self.assertRaises(RuntimeError):
fbb.TypedVectorFromElements(['string', 423])
def test_empty_vector(self):
for bw in 1, 2, 4, 8:
for ebw in 1, 2, 4, 8:
data = bytes([
*uint_bytes(0, ebw),
# Root
*uint_bytes(0, bw),
packed_type(Type.VECTOR, ebw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsVector)
self.assertEqual(len(root.AsVector), 0)
self.assertEqual(flexbuffers.Loads(data), [])
def test_vector1(self):
vector = [300, 400, 500]
for bw in 1, 2, 4, 8:
for ebw in 2, 4, 8:
for tbw_ignored in 1, 2, 4, 8:
with self.subTest(bw=bw, ebw=ebw, ignore=tbw_ignored):
data = bytes([
# Vector length
*uint_bytes(len(vector), ebw),
# Vector elements
*int_bytes(vector[0], ebw),
*int_bytes(vector[1], ebw),
*int_bytes(vector[2], ebw),
# Vector types
packed_type(Type.INT, tbw_ignored),
packed_type(Type.INT, tbw_ignored),
packed_type(Type.INT, tbw_ignored),
# Root
*uint_bytes(ebw * len(vector) + len(vector), bw),
packed_type(Type.VECTOR, ebw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsVector)
self.assertFalse(root.IsMap)
v = root.AsVector
self.assertEqual(len(v), len(vector))
for i in range(len(v)):
self.assertTrue(v[i].IsInt)
self.assertEqual(v[i].AsInt, vector[i])
for i, e in enumerate(v):
self.assertTrue(e.IsInt)
self.assertEqual(e.AsInt, vector[i])
with self.assertRaises(IndexError):
v[-1].AsInt # pylint: disable=pointless-statement
with self.assertRaises(IndexError):
v[3].AsInt # pylint: disable=pointless-statement
with self.assertRaises(TypeError):
root.AsMap # pylint: disable=pointless-statement
self.assertEqual(root.AsInt, len(vector))
self.assertEqual(root.AsFloat, float(len(vector)))
self.assertEqual(flexbuffers.Loads(data), vector)
def test_vector2(self):
vector = [1984, 'August', True]
for bw in 1, 2, 4, 8:
with self.subTest(bw=bw):
data = bytes([
*str_bytes(vector[1], 1),
# Vector
*uint_bytes(len(vector), 2),
*int_bytes(vector[0], 2),
*uint_bytes(11, 2), # offset to 'August'
*uint_bytes(int(vector[2]), 2),
packed_type(Type.INT, 2),
packed_type(Type.STRING, 1),
packed_type(Type.BOOL, 2),
# Root
*uint_bytes(2 * len(vector) + len(vector), bw), # offset to vector
packed_type(Type.VECTOR, 2),
bw,
])
self.assertEqual(flexbuffers.Loads(data), vector)
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsVector)
v = root.AsVector
self.assertTrue(v[0].IsInt)
self.assertEqual(v[0].AsInt, 1984)
self.assertTrue(v[1].IsString)
self.assertEqual(v[1].AsString, 'August')
self.assertTrue(v[2].IsBool)
self.assertTrue(v[2].AsBool)
self.assertEqual(v.Value, vector)
self.assertEqual(root.AsInt, len(vector))
def test_empty_map(self):
for bw in 1, 2, 4, 8:
for kbw in 1, 2, 4, 8:
for vbw in 1, 2, 4, 8:
data = bytes([
*uint_bytes(0, kbw), # Keys length
*uint_bytes(0, vbw),
*uint_bytes(kbw, vbw),
*uint_bytes(0, vbw), # Values length
# Root
*uint_bytes(0, bw),
packed_type(Type.MAP, vbw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsMap)
self.assertEqual(len(root.AsMap), 0)
self.assertEqual(flexbuffers.Loads(data), {})
def test_map(self):
value = {'foo': 13, 'bar': 14}
for bw in 1, 2, 4, 8:
for kbw in 1, 2, 4, 8:
for vbw in 1, 2, 4, 8:
with self.subTest(kbw=kbw, vbw=vbw, bw=bw):
data = bytes([
*key_bytes('foo'), # 4 bytes
*key_bytes('bar'), # 4 bytes
# Map
*uint_bytes(len(value), kbw),
*uint_bytes(4 + 1 * kbw, kbw), # offset to 'bar'
*uint_bytes(8 + 2 * kbw, kbw), # offset to 'foo'
*uint_bytes(len(value) * kbw, vbw), # offset to keys
*uint_bytes(kbw, vbw),
*uint_bytes(len(value), vbw),
*int_bytes(value['bar'], vbw),
*int_bytes(value['foo'], vbw),
packed_type(Type.INT, vbw),
packed_type(Type.INT, vbw),
# Root
*uint_bytes(vbw * len(value) + len(value),
bw), # offset to values
packed_type(Type.MAP, vbw),
bw,
])
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsMap)
m = root.AsMap
self.assertEqual(len(m), 2)
self.assertEqual(m[0].AsInt, 14)
self.assertEqual(m[1].AsInt, 13)
self.assertEqual(m['bar'].AsInt, 14)
self.assertEqual(m['foo'].AsInt, 13)
for invalid_key in 'a', 'b', 'no':
with self.assertRaises(KeyError):
m[invalid_key] # pylint: disable=pointless-statement
values = m.Values
self.assertEqual(len(values), 2)
self.assertEqual(values[0].AsInt, 14)
self.assertEqual(values[1].AsInt, 13)
keys = m.Keys
self.assertEqual(len(keys), 2)
self.assertEqual(len(keys[0].AsKey), 3)
self.assertEqual(keys[0].AsKey, 'bar')
self.assertEqual(len(keys[1].AsKey), 3)
self.assertEqual(keys[1].AsKey, 'foo')
keys = [key.AsKey for key in keys]
self.assertEqual(sorted(keys), keys)
self.assertEqual(root.AsInt, len(value))
self.assertEqual(flexbuffers.Loads(data), value)
def test_alignment(self):
value = ['test', 7]
data = bytes([
*key_bytes('test'), # 5 bytes: 'test' and \0
0,
0,
0, # 3 bytes: alignment
# Vector
*uint_bytes(len(value), byte_width=8),
*uint_bytes(16, byte_width=8),
*uint_bytes(7, byte_width=8),
packed_type(Type.KEY, 1),
packed_type(Type.INT, 8),
# Root
*uint_bytes(8 * len(value) + len(value), 1),
packed_type(Type.VECTOR, 8),
1,
])
self.assertEqual(flexbuffers.Loads(data), value)
class EncoderTest(unittest.TestCase):
"""Tests to check FlexBuffer encoding functions."""
def test_null(self):
def encode_null():
fbb = flexbuffers.Builder()
fbb.Null()
return fbb.Finish()
self.assertIsNone(flexbuffers.Loads(encode_null()))
def test_bool(self):
for value in False, True:
data = encode_type(Type.BOOL, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_int(self):
for byte_width in 1, 2, 4, 8:
for type_ in Type.INT, Type.INDIRECT_INT, Type.UINT, Type.INDIRECT_UINT:
with self.subTest(byte_width=byte_width, type=type_):
value = min_value(type_, byte_width)
data = encode_type(type_, value)
self.assertEqual(flexbuffers.Loads(data), value)
value = max_value(type_, byte_width)
data = encode_type(type_, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_float(self):
for value in 3.141592, 7.62, 999.99:
for type_ in Type.FLOAT, Type.INDIRECT_FLOAT:
with self.subTest(value=value, type=type_):
data = encode_type(type_, value)
self.assertEqual(flexbuffers.Loads(data), value)
data = encode_type(type_, value, 4)
self.assertAlmostEqual(flexbuffers.Loads(data), value, places=4)
data = encode_type(type_, value, 8)
self.assertEqual(flexbuffers.Loads(data), value)
def test_string(self):
for value in '', 'x', 'color', 'hello world':
with self.subTest(value=value):
data = encode_type(Type.STRING, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_blob(self):
for value in bytes(), bytes([240, 12, 143, 7]), bytes(1000 * [17]):
with self.subTest(value=value):
data = encode_type(Type.BLOB, value)
self.assertEqual(flexbuffers.Loads(data), value)
def test_key(self):
for value in '', 'color', 'hello world':
with self.subTest(value=value):
data = encode_type(Type.KEY, value)
self.assertEqual(flexbuffers.Loads(data), value)
with self.assertRaises(ValueError):
encode_type(Type.KEY, (b'\x00' * 10).decode('ascii'))
def test_vector(self):
def encode_vector(elements, element_type):
fbb = flexbuffers.Builder()
with fbb.Vector():
add = fbb.Adder(element_type)
for e in elements:
add(e)
return fbb.Finish()
def encode_vector_from_elements(elements):
fbb = flexbuffers.Builder()
fbb.VectorFromElements(elements)
return fbb.Finish()
for elements in [], [1435], [56, 23, 0, 6783]:
data = encode_vector(elements, Type.INT)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
# Elements of different type: one by one
elements = [56.0, 'flexbuffers', 0, False, 75123]
fbb = flexbuffers.Builder()
with fbb.Vector():
fbb.Float(elements[0])
fbb.String(elements[1])
fbb.UInt(elements[2], 8)
fbb.Bool(elements[3])
fbb.Int(elements[4])
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), elements)
# Elements of different type: all at once
fbb = flexbuffers.Builder()
fbb.VectorFromElements(elements)
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), elements)
def test_nested_vectors(self):
fbb = flexbuffers.Builder()
with fbb.Vector():
fbb.String('begin')
fbb.IndirectInt(42)
with fbb.Vector():
for i in range(5):
fbb.Int(i)
fbb.String('end')
data = fbb.Finish()
self.assertEqual(
flexbuffers.Loads(data), ['begin', 42, [0, 1, 2, 3, 4], 'end'])
def test_big_vector(self):
n = 10 * 1000
fbb = flexbuffers.Builder()
with fbb.Vector():
for i in range(n):
fbb.Int(i)
self.assertEqual(flexbuffers.Loads(fbb.Finish()), list(range(n)))
def test_typed_vector(self):
def encode_typed_vector_from_elements(elements, element_type=None):
fbb = flexbuffers.Builder()
fbb.TypedVectorFromElements(elements, element_type)
return fbb.Finish()
for elements in [], [False], [True], [False, True, True, False, False]:
data = encode_typed_vector_from_elements(elements, Type.BOOL)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
for elements in [], [23455], [351, -2, 0, 6783, 0, -10]:
data = encode_typed_vector_from_elements(elements, Type.INT)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
for elements in [], [23455], [351, 2, 0, 6783, 0, 10]:
data = encode_typed_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements, Type.INT)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements, Type.UINT)
self.assertEqual(flexbuffers.Loads(data), elements)
for elements in [], [7.0], [52.0, 51.2, 70.0, -4.0]:
data = encode_typed_vector_from_elements(elements, Type.FLOAT)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
for elements in [], ['color'], ['x', 'y']:
data = encode_typed_vector_from_elements(elements, Type.KEY)
self.assertEqual(flexbuffers.Loads(data), elements)
data = encode_typed_vector_from_elements(elements)
self.assertEqual(flexbuffers.Loads(data), elements)
def test_typed_vector_from_array(self):
def encode_array(typecode, values):
fbb = flexbuffers.Builder()
fbb.VectorFromElements(array.array(typecode, values))
return fbb.Finish()
values = [1.0, 3.14, -2.54, 0.0]
data = encode_array('f', values)
for a, b in zip(flexbuffers.Loads(data), values):
self.assertAlmostEqual(a, b, places=2)
values = [1.0, 3.14, -2.54, 0.0]
data = encode_array('d', values)
self.assertEqual(flexbuffers.Loads(data), values)
values = [1, -7, 9, 26, 12]
data = encode_array('i', values)
self.assertEqual(flexbuffers.Loads(data), values)
values = [0, 1, 2, 3, 4, 5, 6]
data = encode_array('I', values)
self.assertEqual(flexbuffers.Loads(data), values)
def test_fixed_typed_vector(self):
def encode_fixed_typed_vector(elements, element_type=None):
fbb = flexbuffers.Builder()
fbb.FixedTypedVectorFromElements(elements, element_type)
return fbb.Finish()
for elements in ((-2, 2), (1, 2, 3), (100, -100, 200, -200), (4.0, 7.0),
(0.0, 1.0, 8.0), (9.0, 7.0, 1.0, 5.5)):
with self.subTest(elements=elements):
data = encode_fixed_typed_vector(elements)
self.assertSequenceEqual(flexbuffers.Loads(data), elements)
elements = [-170, 432, 0, -7]
data = encode_fixed_typed_vector(elements, Type.INT)
self.assertSequenceEqual(flexbuffers.Loads(data), elements)
with self.assertRaises(ValueError):
encode_fixed_typed_vector([]) # Invalid input length
with self.assertRaises(ValueError):
encode_fixed_typed_vector([1]) # Invalid input length
with self.assertRaises(ValueError):
encode_fixed_typed_vector([1, 2, 3, 4, 5]) # Invalid input length
with self.assertRaises(TypeError):
encode_fixed_typed_vector([1, 1.0]) # Invalid input types
with self.assertRaises(TypeError):
encode_fixed_typed_vector(['', '']) # Invalid input types
def test_map_builder(self):
def get_keys(data):
return [key.AsKey for key in flexbuffers.GetRoot(data).AsMap.Keys]
# Empty map
fbb = flexbuffers.Builder()
with fbb.Map():
pass
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), {})
# Two-element map of Int
fbb = flexbuffers.Builder()
with fbb.Map():
fbb.Int('y', -2)
fbb.Int('x', 10)
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), {'x': 10, 'y': -2})
# Multiple-element map of vectors
fbb = flexbuffers.Builder()
with fbb.Map():
with fbb.Vector('v'):
fbb.Int(45)
with fbb.TypedVector('tv'):
fbb.Int(-7)
fbb.FixedTypedVectorFromElements('ftv', [-2.0, 1.0])
data = fbb.Finish()
self.assertEqual(
flexbuffers.Loads(data), {
'v': [45],
'tv': [-7],
'ftv': [-2.0, 1.0]
})
keys = get_keys(data)
self.assertEqual(sorted(keys), keys)
# Multiple-element map of different types
fbb = flexbuffers.Builder()
with fbb.Map():
fbb.Null('n')
fbb.Bool('b', False)
fbb.Int('i', -27)
fbb.UInt('u', 27)
fbb.Float('f', -0.85)
fbb.String('s', 'String')
fbb.Blob('bb', b'data')
fbb.IndirectInt('ii', -9500)
fbb.IndirectUInt('iu', 540)
fbb.IndirectFloat('if', 0.0)
fbb.VectorFromElements('v', [2, 1, 0.0])
fbb.TypedVectorFromElements('tv', [2, 1, 0])
fbb.FixedTypedVectorFromElements('ftv', [2.0, -6.0])
data = fbb.Finish()
self.assertEqual(
flexbuffers.Loads(data), {
'n': None,
'b': False,
'i': -27,
'u': 27,
'f': -0.85,
's': 'String',
'bb': b'data',
'ii': -9500,
'iu': 540,
'if': 0.0,
'v': [2, 1, 0.0],
'tv': [2, 1, 0],
'ftv': [2.0, -6.0]
})
keys = get_keys(data)
self.assertEqual(sorted(keys), keys)
def test_map_python(self):
maps = [
{},
{
'key': 'value'
},
{
'x': None,
'y': 3400,
'z': -7040
},
{
'zzz': 100,
'aaa': 5.0,
'ccc': ['Test', 32, False, None, True]
},
{
'name': ['John', 'Smith'],
'valid': True,
'note': None,
'address': {
'lines': [175, 'Alhambra'],
'city': 'San Francisco',
'zip': 94123,
},
},
]
for m in maps:
self.assertEqual(flexbuffers.Loads(flexbuffers.Dumps(m)), m)
def test_gold_from_file(self):
data = read_test_file(GOLD_FLEXBUFFER_FILE)
self.assertEqual(flexbuffers.Loads(data), GOLD_FLEXBUFFER_OBJ)
def test_gold_from_builder(self):
fbb = flexbuffers.Builder()
with fbb.Map():
with fbb.Vector('vec'):
fbb.Int(-100)
fbb.String('Fred')
fbb.IndirectFloat(4.0)
i_f = fbb.LastValue
fbb.Blob(bytes([77]))
fbb.Bool(False)
fbb.ReuseValue(i_f)
vec = [1, 2, 3]
fbb.VectorFromElements('bar', vec)
fbb.FixedTypedVectorFromElements('bar3', [1, 2, 3])
fbb.VectorFromElements('bools', [True, False, True, False])
fbb.Bool('bool', True)
fbb.Float('foo', 100)
with fbb.Map('mymap'):
fbb.String('foo', 'Fred')
data = fbb.Finish()
self.assertEqual(flexbuffers.Loads(data), GOLD_FLEXBUFFER_OBJ)
def test_min_bit_width(self):
fbb = flexbuffers.Builder(force_min_bit_width=flexbuffers.BitWidth.W8)
fbb.TypedVectorFromElements([0, 1, 0, 1, 0])
data = fbb.Finish()
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsTypedVector)
self.assertEqual(root.AsTypedVector.ByteWidth, 1)
fbb = flexbuffers.Builder(force_min_bit_width=flexbuffers.BitWidth.W32)
fbb.TypedVectorFromElements([0, 1, 0, 1, 0])
data = fbb.Finish()
root = flexbuffers.GetRoot(data)
self.assertTrue(root.IsTypedVector)
self.assertEqual(root.AsTypedVector.ByteWidth, 4)
def test_share_keys(self):
def encode_key_vector(value, count, share_keys):
fbb = flexbuffers.Builder(share_keys=share_keys)
with fbb.Vector():
for _ in range(count):
fbb.Key(value)
return fbb.Finish(), fbb.KeyPool.Elements
data, pool = encode_key_vector('test', 10, share_keys=False)
self.assertEqual(len(pool), 0)
self.assertEqual(len(data), 74)
self.assertEqual(flexbuffers.Loads(data), 10 * ['test'])
data, pool = encode_key_vector('test', 10, share_keys=True)
self.assertEqual(len(pool), 1)
self.assertEqual(pool[0], 'test'.encode('ascii'))
self.assertEqual(len(data), 29)
self.assertEqual(flexbuffers.Loads(data), 10 * ['test'])
def test_share_strings(self):
def encode_string_vector(value, count, share_strings):
fbb = flexbuffers.Builder(share_strings=share_strings)
with fbb.Vector():
for _ in range(count):
fbb.String(value)
return fbb.Finish(), fbb.StringPool.Elements
data, pool = encode_string_vector('test', 10, share_strings=False)
self.assertEqual(len(pool), 0)
self.assertEqual(len(data), 84)
self.assertEqual(flexbuffers.Loads(data), 10 * ['test'])
data, pool = encode_string_vector('test', 10, share_strings=True)
self.assertEqual(len(pool), 1)
self.assertEqual(pool[0], 'test'.encode('utf-8'))
self.assertEqual(len(data), 30)
self.assertEqual(flexbuffers.Loads(data), 10 * ['test'])
def test_invalid_stack_size(self):
fbb = flexbuffers.Builder()
with self.assertRaises(RuntimeError):
fbb.Finish()
fbb.Int(100)
fbb.Int(200)
with self.assertRaises(RuntimeError):
fbb.Finish()
fbb.Clear()
fbb.Int(420)
fbb.Finish()
if __name__ == '__main__':
unittest.main()