# 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()