• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding=utf-8
2# Copyright 2014 Google Inc. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os.path
17import sys
18import imp
19PY_VERSION = sys.version_info[:2]
20
21import ctypes
22from collections import defaultdict
23import timeit
24import unittest
25
26
27from flatbuffers import compat
28from flatbuffers.compat import range_func as compat_range
29from flatbuffers.compat import NumpyRequiredForThisFeature
30
31import flatbuffers
32from flatbuffers import number_types as N
33
34import MyGame  # refers to generated code
35import MyGame.Example  # refers to generated code
36import MyGame.Example.Any  # refers to generated code
37import MyGame.Example.Color  # refers to generated code
38import MyGame.Example.Monster  # refers to generated code
39import MyGame.Example.Test  # refers to generated code
40import MyGame.Example.Stat  # refers to generated code
41import MyGame.Example.Vec3  # refers to generated code
42
43
44def assertRaises(test_case, fn, exception_class):
45    ''' Backwards-compatible assertion for exceptions raised. '''
46
47    exc = None
48    try:
49        fn()
50    except Exception as e:
51        exc = e
52    test_case.assertTrue(exc is not None)
53    test_case.assertTrue(isinstance(exc, exception_class))
54
55
56class TestWireFormat(unittest.TestCase):
57    def test_wire_format(self):
58        # Verify that using the generated Python code builds a buffer without
59        # returning errors, and is interpreted correctly:
60        gen_buf, gen_off = make_monster_from_generated_code()
61        CheckReadBuffer(gen_buf, gen_off)
62
63        # Verify that the canonical flatbuffer file is readable by the
64        # generated Python code. Note that context managers are not part of
65        # Python 2.5, so we use the simpler open/close methods here:
66        f = open('monsterdata_test.mon', 'rb')
67        canonicalWireData = f.read()
68        f.close()
69        CheckReadBuffer(bytearray(canonicalWireData), 0)
70
71        # Write the generated buffer out to a file:
72        f = open('monsterdata_python_wire.mon', 'wb')
73        f.write(gen_buf[gen_off:])
74        f.close()
75
76
77def CheckReadBuffer(buf, offset):
78    ''' CheckReadBuffer checks that the given buffer is evaluated correctly
79        as the example Monster. '''
80
81    def asserter(stmt):
82        ''' An assertion helper that is separated from TestCase classes. '''
83        if not stmt:
84            raise AssertionError('CheckReadBuffer case failed')
85
86    monster = MyGame.Example.Monster.Monster.GetRootAsMonster(buf, offset)
87
88    asserter(monster.Hp() == 80)
89    asserter(monster.Mana() == 150)
90    asserter(monster.Name() == b'MyMonster')
91
92    # initialize a Vec3 from Pos()
93    vec = monster.Pos()
94    asserter(vec is not None)
95
96    # verify the properties of the Vec3
97    asserter(vec.X() == 1.0)
98    asserter(vec.Y() == 2.0)
99    asserter(vec.Z() == 3.0)
100    asserter(vec.Test1() == 3.0)
101    asserter(vec.Test2() == 2)
102
103    # initialize a Test from Test3(...)
104    t = MyGame.Example.Test.Test()
105    t = vec.Test3(t)
106    asserter(t is not None)
107
108    # verify the properties of the Test
109    asserter(t.A() == 5)
110    asserter(t.B() == 6)
111
112    # verify that the enum code matches the enum declaration:
113    union_type = MyGame.Example.Any.Any
114    asserter(monster.TestType() == union_type.Monster)
115
116    # initialize a Table from a union field Test(...)
117    table2 = monster.Test()
118    asserter(type(table2) is flatbuffers.table.Table)
119
120    # initialize a Monster from the Table from the union
121    monster2 = MyGame.Example.Monster.Monster()
122    monster2.Init(table2.Bytes, table2.Pos)
123
124    asserter(monster2.Name() == b"Fred")
125
126    # iterate through the first monster's inventory:
127    asserter(monster.InventoryLength() == 5)
128
129    invsum = 0
130    for i in compat_range(monster.InventoryLength()):
131        v = monster.Inventory(i)
132        invsum += int(v)
133    asserter(invsum == 10)
134
135    for i in range(5):
136        asserter(monster.VectorOfLongs(i) == 10 ** (i * 2))
137
138    asserter(([-1.7976931348623157e+308, 0, 1.7976931348623157e+308]
139              == [monster.VectorOfDoubles(i)
140                  for i in range(monster.VectorOfDoublesLength())]))
141
142    try:
143        imp.find_module('numpy')
144        # if numpy exists, then we should be able to get the
145        # vector as a numpy array
146        import numpy as np
147
148        asserter(monster.InventoryAsNumpy().sum() == 10)
149        asserter(monster.InventoryAsNumpy().dtype == np.dtype('uint8'))
150
151        VectorOfLongs = monster.VectorOfLongsAsNumpy()
152        asserter(VectorOfLongs.dtype == np.dtype('int64'))
153        for i in range(5):
154            asserter(VectorOfLongs[i] == 10 ** (i * 2))
155
156        VectorOfDoubles = monster.VectorOfDoublesAsNumpy()
157        asserter(VectorOfDoubles.dtype == np.dtype('float64'))
158        asserter(VectorOfDoubles[0] == np.finfo('float64').min)
159        asserter(VectorOfDoubles[1] == 0.0)
160        asserter(VectorOfDoubles[2] == np.finfo('float64').max)
161
162    except ImportError:
163        # If numpy does not exist, trying to get vector as numpy
164        # array should raise NumpyRequiredForThisFeature. The way
165        # assertRaises has been implemented prevents us from
166        # asserting this error is raised outside of a test case.
167        pass
168
169    asserter(monster.Test4Length() == 2)
170
171    # create a 'Test' object and populate it:
172    test0 = monster.Test4(0)
173    asserter(type(test0) is MyGame.Example.Test.Test)
174
175    test1 = monster.Test4(1)
176    asserter(type(test1) is MyGame.Example.Test.Test)
177
178    # the position of test0 and test1 are swapped in monsterdata_java_wire
179    # and monsterdata_test_wire, so ignore ordering
180    v0 = test0.A()
181    v1 = test0.B()
182    v2 = test1.A()
183    v3 = test1.B()
184    sumtest12 = int(v0) + int(v1) + int(v2) + int(v3)
185
186    asserter(sumtest12 == 100)
187
188    asserter(monster.TestarrayofstringLength() == 2)
189    asserter(monster.Testarrayofstring(0) == b"test1")
190    asserter(monster.Testarrayofstring(1) == b"test2")
191
192    asserter(monster.TestarrayoftablesLength() == 0)
193    asserter(monster.TestnestedflatbufferLength() == 0)
194    asserter(monster.Testempty() is None)
195
196
197class TestFuzz(unittest.TestCase):
198    ''' Low level stress/fuzz test: serialize/deserialize a variety of
199        different kinds of data in different combinations '''
200
201    binary_type = compat.binary_types[0] # this will always exist
202    ofInt32Bytes = binary_type([0x83, 0x33, 0x33, 0x33])
203    ofInt64Bytes = binary_type([0x84, 0x44, 0x44, 0x44,
204                                0x44, 0x44, 0x44, 0x44])
205    overflowingInt32Val = flatbuffers.encode.Get(flatbuffers.packer.int32,
206                                                 ofInt32Bytes, 0)
207    overflowingInt64Val = flatbuffers.encode.Get(flatbuffers.packer.int64,
208                                                 ofInt64Bytes, 0)
209
210    # Values we're testing against: chosen to ensure no bits get chopped
211    # off anywhere, and also be different from eachother.
212    boolVal = True
213    int8Val = N.Int8Flags.py_type(-127) # 0x81
214    uint8Val = N.Uint8Flags.py_type(0xFF)
215    int16Val = N.Int16Flags.py_type(-32222) # 0x8222
216    uint16Val = N.Uint16Flags.py_type(0xFEEE)
217    int32Val = N.Int32Flags.py_type(overflowingInt32Val)
218    uint32Val = N.Uint32Flags.py_type(0xFDDDDDDD)
219    int64Val = N.Int64Flags.py_type(overflowingInt64Val)
220    uint64Val = N.Uint64Flags.py_type(0xFCCCCCCCCCCCCCCC)
221    # Python uses doubles, so force it here
222    float32Val = N.Float32Flags.py_type(ctypes.c_float(3.14159).value)
223    float64Val = N.Float64Flags.py_type(3.14159265359)
224
225    def test_fuzz(self):
226        return self.check_once(11, 100)
227
228    def check_once(self, fuzzFields, fuzzObjects):
229        testValuesMax = 11 # hardcoded to the number of scalar types
230
231        builder = flatbuffers.Builder(0)
232        l = LCG()
233
234        objects = [0 for _ in compat_range(fuzzObjects)]
235
236        # Generate fuzzObjects random objects each consisting of
237        # fuzzFields fields, each of a random type.
238        for i in compat_range(fuzzObjects):
239            builder.StartObject(fuzzFields)
240
241            for j in compat_range(fuzzFields):
242                choice = int(l.Next()) % testValuesMax
243                if choice == 0:
244                    builder.PrependBoolSlot(int(j), self.boolVal, False)
245                elif choice == 1:
246                    builder.PrependInt8Slot(int(j), self.int8Val, 0)
247                elif choice == 2:
248                    builder.PrependUint8Slot(int(j), self.uint8Val, 0)
249                elif choice == 3:
250                    builder.PrependInt16Slot(int(j), self.int16Val, 0)
251                elif choice == 4:
252                    builder.PrependUint16Slot(int(j), self.uint16Val, 0)
253                elif choice == 5:
254                    builder.PrependInt32Slot(int(j), self.int32Val, 0)
255                elif choice == 6:
256                    builder.PrependUint32Slot(int(j), self.uint32Val, 0)
257                elif choice == 7:
258                    builder.PrependInt64Slot(int(j), self.int64Val, 0)
259                elif choice == 8:
260                    builder.PrependUint64Slot(int(j), self.uint64Val, 0)
261                elif choice == 9:
262                    builder.PrependFloat32Slot(int(j), self.float32Val, 0)
263                elif choice == 10:
264                    builder.PrependFloat64Slot(int(j), self.float64Val, 0)
265                else:
266                    raise RuntimeError('unreachable')
267
268            off = builder.EndObject()
269
270            # store the offset from the end of the builder buffer,
271            # since it will keep growing:
272            objects[i] = off
273
274        # Do some bookkeeping to generate stats on fuzzes:
275        stats = defaultdict(int)
276        def check(table, desc, want, got):
277            stats[desc] += 1
278            self.assertEqual(want, got, "%s != %s, %s" % (want, got, desc))
279
280        l = LCG()  # Reset.
281
282        # Test that all objects we generated are readable and return the
283        # expected values. We generate random objects in the same order
284        # so this is deterministic.
285        for i in compat_range(fuzzObjects):
286
287            table = flatbuffers.table.Table(builder.Bytes,
288                                            len(builder.Bytes) - objects[i])
289
290            for j in compat_range(fuzzFields):
291                field_count = flatbuffers.builder.VtableMetadataFields + j
292                f = N.VOffsetTFlags.py_type(field_count *
293                                            N.VOffsetTFlags.bytewidth)
294                choice = int(l.Next()) % testValuesMax
295
296                if choice == 0:
297                    check(table, "bool", self.boolVal,
298                          table.GetSlot(f, False, N.BoolFlags))
299                elif choice == 1:
300                    check(table, "int8", self.int8Val,
301                          table.GetSlot(f, 0, N.Int8Flags))
302                elif choice == 2:
303                    check(table, "uint8", self.uint8Val,
304                          table.GetSlot(f, 0, N.Uint8Flags))
305                elif choice == 3:
306                    check(table, "int16", self.int16Val,
307                          table.GetSlot(f, 0, N.Int16Flags))
308                elif choice == 4:
309                    check(table, "uint16", self.uint16Val,
310                          table.GetSlot(f, 0, N.Uint16Flags))
311                elif choice == 5:
312                    check(table, "int32", self.int32Val,
313                          table.GetSlot(f, 0, N.Int32Flags))
314                elif choice == 6:
315                    check(table, "uint32", self.uint32Val,
316                          table.GetSlot(f, 0, N.Uint32Flags))
317                elif choice == 7:
318                    check(table, "int64", self.int64Val,
319                          table.GetSlot(f, 0, N.Int64Flags))
320                elif choice == 8:
321                    check(table, "uint64", self.uint64Val,
322                          table.GetSlot(f, 0, N.Uint64Flags))
323                elif choice == 9:
324                    check(table, "float32", self.float32Val,
325                          table.GetSlot(f, 0, N.Float32Flags))
326                elif choice == 10:
327                    check(table, "float64", self.float64Val,
328                          table.GetSlot(f, 0, N.Float64Flags))
329                else:
330                    raise RuntimeError('unreachable')
331
332        # If enough checks were made, verify that all scalar types were used:
333        self.assertEqual(testValuesMax, len(stats),
334                "fuzzing failed to test all scalar types: %s" % stats)
335
336
337class TestByteLayout(unittest.TestCase):
338    ''' TestByteLayout checks the bytes of a Builder in various scenarios. '''
339
340    def assertBuilderEquals(self, builder, want_chars_or_ints):
341        def integerize(x):
342            if isinstance(x, compat.string_types):
343                return ord(x)
344            return x
345
346        want_ints = list(map(integerize, want_chars_or_ints))
347        want = bytearray(want_ints)
348        got = builder.Bytes[builder.Head():] # use the buffer directly
349        self.assertEqual(want, got)
350
351    def test_numbers(self):
352        b = flatbuffers.Builder(0)
353        self.assertBuilderEquals(b, [])
354        b.PrependBool(True)
355        self.assertBuilderEquals(b, [1])
356        b.PrependInt8(-127)
357        self.assertBuilderEquals(b, [129, 1])
358        b.PrependUint8(255)
359        self.assertBuilderEquals(b, [255, 129, 1])
360        b.PrependInt16(-32222)
361        self.assertBuilderEquals(b, [0x22, 0x82, 0, 255, 129, 1]) # first pad
362        b.PrependUint16(0xFEEE)
363        # no pad this time:
364        self.assertBuilderEquals(b, [0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1])
365        b.PrependInt32(-53687092)
366        self.assertBuilderEquals(b, [204, 204, 204, 252, 0xEE, 0xFE,
367                                     0x22, 0x82, 0, 255, 129, 1])
368        b.PrependUint32(0x98765432)
369        self.assertBuilderEquals(b, [0x32, 0x54, 0x76, 0x98,
370                                     204, 204, 204, 252,
371                                     0xEE, 0xFE, 0x22, 0x82,
372                                     0, 255, 129, 1])
373
374    def test_numbers64(self):
375        b = flatbuffers.Builder(0)
376        b.PrependUint64(0x1122334455667788)
377        self.assertBuilderEquals(b, [0x88, 0x77, 0x66, 0x55,
378                                     0x44, 0x33, 0x22, 0x11])
379
380        b = flatbuffers.Builder(0)
381        b.PrependInt64(0x1122334455667788)
382        self.assertBuilderEquals(b, [0x88, 0x77, 0x66, 0x55,
383                                     0x44, 0x33, 0x22, 0x11])
384
385    def test_1xbyte_vector(self):
386        b = flatbuffers.Builder(0)
387        self.assertBuilderEquals(b, [])
388        b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 1, 1)
389        self.assertBuilderEquals(b, [0, 0, 0]) # align to 4bytes
390        b.PrependByte(1)
391        self.assertBuilderEquals(b, [1, 0, 0, 0])
392        b.EndVector(1)
393        self.assertBuilderEquals(b, [1, 0, 0, 0, 1, 0, 0, 0]) # padding
394
395    def test_2xbyte_vector(self):
396        b = flatbuffers.Builder(0)
397        b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 2, 1)
398        self.assertBuilderEquals(b, [0, 0]) # align to 4bytes
399        b.PrependByte(1)
400        self.assertBuilderEquals(b, [1, 0, 0])
401        b.PrependByte(2)
402        self.assertBuilderEquals(b, [2, 1, 0, 0])
403        b.EndVector(2)
404        self.assertBuilderEquals(b, [2, 0, 0, 0, 2, 1, 0, 0]) # padding
405
406    def test_1xuint16_vector(self):
407        b = flatbuffers.Builder(0)
408        b.StartVector(flatbuffers.number_types.Uint16Flags.bytewidth, 1, 1)
409        self.assertBuilderEquals(b, [0, 0]) # align to 4bytes
410        b.PrependUint16(1)
411        self.assertBuilderEquals(b, [1, 0, 0, 0])
412        b.EndVector(1)
413        self.assertBuilderEquals(b, [1, 0, 0, 0, 1, 0, 0, 0]) # padding
414
415    def test_2xuint16_vector(self):
416        b = flatbuffers.Builder(0)
417        b.StartVector(flatbuffers.number_types.Uint16Flags.bytewidth, 2, 1)
418        self.assertBuilderEquals(b, []) # align to 4bytes
419        b.PrependUint16(0xABCD)
420        self.assertBuilderEquals(b, [0xCD, 0xAB])
421        b.PrependUint16(0xDCBA)
422        self.assertBuilderEquals(b, [0xBA, 0xDC, 0xCD, 0xAB])
423        b.EndVector(2)
424        self.assertBuilderEquals(b, [2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB])
425
426    def test_create_ascii_string(self):
427        b = flatbuffers.Builder(0)
428        b.CreateString(u"foo", encoding='ascii')
429
430        # 0-terminated, no pad:
431        self.assertBuilderEquals(b, [3, 0, 0, 0, 'f', 'o', 'o', 0])
432        b.CreateString(u"moop", encoding='ascii')
433        # 0-terminated, 3-byte pad:
434        self.assertBuilderEquals(b, [4, 0, 0, 0, 'm', 'o', 'o', 'p',
435                                     0, 0, 0, 0,
436                                     3, 0, 0, 0, 'f', 'o', 'o', 0])
437
438    def test_create_utf8_string(self):
439        b = flatbuffers.Builder(0)
440        b.CreateString(u"Цлїςσδε")
441        self.assertBuilderEquals(b, "\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
442            "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
443
444        b.CreateString(u"フムアムカモケモ")
445        self.assertBuilderEquals(b, "\x18\x00\x00\x00\xef\xbe\x8c\xef\xbe\x91" \
446            "\xef\xbd\xb1\xef\xbe\x91\xef\xbd\xb6\xef\xbe\x93\xef\xbd\xb9\xef" \
447            "\xbe\x93\x00\x00\x00\x00\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
448            "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
449
450    def test_create_arbitrary_string(self):
451        b = flatbuffers.Builder(0)
452        s = "\x01\x02\x03"
453        b.CreateString(s) # Default encoding is utf-8.
454        # 0-terminated, no pad:
455        self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
456        s2 = "\x04\x05\x06\x07"
457        b.CreateString(s2) # Default encoding is utf-8.
458        # 0-terminated, 3-byte pad:
459        self.assertBuilderEquals(b, [4, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0,
460                                     3, 0, 0, 0, 1, 2, 3, 0])
461
462    def test_create_byte_vector(self):
463        b = flatbuffers.Builder(0)
464        b.CreateByteVector(b"")
465        # 0-byte pad:
466        self.assertBuilderEquals(b, [0, 0, 0, 0])
467
468        b = flatbuffers.Builder(0)
469        b.CreateByteVector(b"\x01\x02\x03")
470        # 1-byte pad:
471        self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
472
473    def test_empty_vtable(self):
474        b = flatbuffers.Builder(0)
475        b.StartObject(0)
476        self.assertBuilderEquals(b, [])
477        b.EndObject()
478        self.assertBuilderEquals(b, [4, 0, 4, 0, 4, 0, 0, 0])
479
480    def test_vtable_with_one_true_bool(self):
481        b = flatbuffers.Builder(0)
482        self.assertBuilderEquals(b, [])
483        b.StartObject(1)
484        self.assertBuilderEquals(b, [])
485        b.PrependBoolSlot(0, True, False)
486        b.EndObject()
487        self.assertBuilderEquals(b, [
488            6, 0,  # vtable bytes
489            8, 0,  # length of object including vtable offset
490            7, 0,  # start of bool value
491            6, 0, 0, 0,  # offset for start of vtable (int32)
492            0, 0, 0,  # padded to 4 bytes
493            1,  # bool value
494        ])
495
496    def test_vtable_with_one_default_bool(self):
497        b = flatbuffers.Builder(0)
498        self.assertBuilderEquals(b, [])
499        b.StartObject(1)
500        self.assertBuilderEquals(b, [])
501        b.PrependBoolSlot(0, False, False)
502        b.EndObject()
503        self.assertBuilderEquals(b, [
504            4, 0,  # vtable bytes
505            4, 0,  # end of object from here
506            # entry 1 is zero and not stored
507            4, 0, 0, 0,  # offset for start of vtable (int32)
508        ])
509
510    def test_vtable_with_one_int16(self):
511        b = flatbuffers.Builder(0)
512        b.StartObject(1)
513        b.PrependInt16Slot(0, 0x789A, 0)
514        b.EndObject()
515        self.assertBuilderEquals(b, [
516            6, 0,  # vtable bytes
517            8, 0,  # end of object from here
518            6, 0,  # offset to value
519            6, 0, 0, 0,  # offset for start of vtable (int32)
520            0, 0,  # padding to 4 bytes
521            0x9A, 0x78,
522        ])
523
524    def test_vtable_with_two_int16(self):
525        b = flatbuffers.Builder(0)
526        b.StartObject(2)
527        b.PrependInt16Slot(0, 0x3456, 0)
528        b.PrependInt16Slot(1, 0x789A, 0)
529        b.EndObject()
530        self.assertBuilderEquals(b, [
531            8, 0,  # vtable bytes
532            8, 0,  # end of object from here
533            6, 0,  # offset to value 0
534            4, 0,  # offset to value 1
535            8, 0, 0, 0,  # offset for start of vtable (int32)
536            0x9A, 0x78,  # value 1
537            0x56, 0x34,  # value 0
538        ])
539
540    def test_vtable_with_int16_and_bool(self):
541        b = flatbuffers.Builder(0)
542        b.StartObject(2)
543        b.PrependInt16Slot(0, 0x3456, 0)
544        b.PrependBoolSlot(1, True, False)
545        b.EndObject()
546        self.assertBuilderEquals(b, [
547            8, 0,  # vtable bytes
548            8, 0,  # end of object from here
549            6, 0,  # offset to value 0
550            5, 0,  # offset to value 1
551            8, 0, 0, 0,  # offset for start of vtable (int32)
552            0,          # padding
553            1,          # value 1
554            0x56, 0x34,  # value 0
555        ])
556
557    def test_vtable_with_empty_vector(self):
558        b = flatbuffers.Builder(0)
559        b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 0, 1)
560        vecend = b.EndVector(0)
561        b.StartObject(1)
562        b.PrependUOffsetTRelativeSlot(0, vecend, 0)
563        b.EndObject()
564        self.assertBuilderEquals(b, [
565            6, 0,  # vtable bytes
566            8, 0,
567            4, 0,  # offset to vector offset
568            6, 0, 0, 0,  # offset for start of vtable (int32)
569            4, 0, 0, 0,
570            0, 0, 0, 0,  # length of vector (not in struct)
571        ])
572
573    def test_vtable_with_empty_vector_of_byte_and_some_scalars(self):
574        b = flatbuffers.Builder(0)
575        b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 0, 1)
576        vecend = b.EndVector(0)
577        b.StartObject(2)
578        b.PrependInt16Slot(0, 55, 0)
579        b.PrependUOffsetTRelativeSlot(1, vecend, 0)
580        b.EndObject()
581        self.assertBuilderEquals(b, [
582            8, 0,  # vtable bytes
583            12, 0,
584            10, 0,  # offset to value 0
585            4, 0,  # offset to vector offset
586            8, 0, 0, 0,  # vtable loc
587            8, 0, 0, 0,  # value 1
588            0, 0, 55, 0,  # value 0
589
590            0, 0, 0, 0,  # length of vector (not in struct)
591        ])
592
593    def test_vtable_with_1_int16_and_2vector_of_int16(self):
594        b = flatbuffers.Builder(0)
595        b.StartVector(flatbuffers.number_types.Int16Flags.bytewidth, 2, 1)
596        b.PrependInt16(0x1234)
597        b.PrependInt16(0x5678)
598        vecend = b.EndVector(2)
599        b.StartObject(2)
600        b.PrependUOffsetTRelativeSlot(1, vecend, 0)
601        b.PrependInt16Slot(0, 55, 0)
602        b.EndObject()
603        self.assertBuilderEquals(b, [
604            8, 0,  # vtable bytes
605            12, 0,  # length of object
606            6, 0,  # start of value 0 from end of vtable
607            8, 0,  # start of value 1 from end of buffer
608            8, 0, 0, 0,  # offset for start of vtable (int32)
609            0, 0,  # padding
610            55, 0,  # value 0
611            4, 0, 0, 0,  # vector position from here
612            2, 0, 0, 0,  # length of vector (uint32)
613            0x78, 0x56,  # vector value 1
614            0x34, 0x12,  # vector value 0
615        ])
616
617    def test_vtable_with_1_struct_of_1_int8__1_int16__1_int32(self):
618        b = flatbuffers.Builder(0)
619        b.StartObject(1)
620        b.Prep(4+4+4, 0)
621        b.PrependInt8(55)
622        b.Pad(3)
623        b.PrependInt16(0x1234)
624        b.Pad(2)
625        b.PrependInt32(0x12345678)
626        structStart = b.Offset()
627        b.PrependStructSlot(0, structStart, 0)
628        b.EndObject()
629        self.assertBuilderEquals(b, [
630            6, 0,  # vtable bytes
631            16, 0,  # end of object from here
632            4, 0,  # start of struct from here
633            6, 0, 0, 0,  # offset for start of vtable (int32)
634            0x78, 0x56, 0x34, 0x12,  # value 2
635            0, 0,  # padding
636            0x34, 0x12,  # value 1
637            0, 0, 0,  # padding
638            55,  # value 0
639        ])
640
641    def test_vtable_with_1_vector_of_2_struct_of_2_int8(self):
642        b = flatbuffers.Builder(0)
643        b.StartVector(flatbuffers.number_types.Int8Flags.bytewidth*2, 2, 1)
644        b.PrependInt8(33)
645        b.PrependInt8(44)
646        b.PrependInt8(55)
647        b.PrependInt8(66)
648        vecend = b.EndVector(2)
649        b.StartObject(1)
650        b.PrependUOffsetTRelativeSlot(0, vecend, 0)
651        b.EndObject()
652        self.assertBuilderEquals(b, [
653            6, 0,  # vtable bytes
654            8, 0,
655            4, 0,  # offset of vector offset
656            6, 0, 0, 0,  # offset for start of vtable (int32)
657            4, 0, 0, 0,  # vector start offset
658
659            2, 0, 0, 0,  # vector length
660            66,  # vector value 1,1
661            55,  # vector value 1,0
662            44,  # vector value 0,1
663            33,  # vector value 0,0
664        ])
665
666    def test_table_with_some_elements(self):
667        b = flatbuffers.Builder(0)
668        b.StartObject(2)
669        b.PrependInt8Slot(0, 33, 0)
670        b.PrependInt16Slot(1, 66, 0)
671        off = b.EndObject()
672        b.Finish(off)
673
674        self.assertBuilderEquals(b, [
675            12, 0, 0, 0,  # root of table: points to vtable offset
676
677            8, 0,  # vtable bytes
678            8, 0,  # end of object from here
679            7, 0,  # start of value 0
680            4, 0,  # start of value 1
681
682            8, 0, 0, 0,  # offset for start of vtable (int32)
683
684            66, 0,  # value 1
685            0,  # padding
686            33,  # value 0
687        ])
688
689    def test__one_unfinished_table_and_one_finished_table(self):
690        b = flatbuffers.Builder(0)
691        b.StartObject(2)
692        b.PrependInt8Slot(0, 33, 0)
693        b.PrependInt8Slot(1, 44, 0)
694        off = b.EndObject()
695        b.Finish(off)
696
697        b.StartObject(3)
698        b.PrependInt8Slot(0, 55, 0)
699        b.PrependInt8Slot(1, 66, 0)
700        b.PrependInt8Slot(2, 77, 0)
701        off = b.EndObject()
702        b.Finish(off)
703
704        self.assertBuilderEquals(b, [
705            16, 0, 0, 0,  # root of table: points to object
706            0, 0,  # padding
707
708            10, 0,  # vtable bytes
709            8, 0,  # size of object
710            7, 0,  # start of value 0
711            6, 0,  # start of value 1
712            5, 0,  # start of value 2
713            10, 0, 0, 0,  # offset for start of vtable (int32)
714            0,  # padding
715            77,  # value 2
716            66,  # value 1
717            55,  # value 0
718
719            12, 0, 0, 0,  # root of table: points to object
720
721            8, 0,  # vtable bytes
722            8, 0,  # size of object
723            7, 0,  # start of value 0
724            6, 0,  # start of value 1
725            8, 0, 0, 0,  # offset for start of vtable (int32)
726            0, 0,  # padding
727            44,  # value 1
728            33,  # value 0
729        ])
730
731    def test_a_bunch_of_bools(self):
732        b = flatbuffers.Builder(0)
733        b.StartObject(8)
734        b.PrependBoolSlot(0, True, False)
735        b.PrependBoolSlot(1, True, False)
736        b.PrependBoolSlot(2, True, False)
737        b.PrependBoolSlot(3, True, False)
738        b.PrependBoolSlot(4, True, False)
739        b.PrependBoolSlot(5, True, False)
740        b.PrependBoolSlot(6, True, False)
741        b.PrependBoolSlot(7, True, False)
742        off = b.EndObject()
743        b.Finish(off)
744
745        self.assertBuilderEquals(b, [
746            24, 0, 0, 0,  # root of table: points to vtable offset
747
748            20, 0,  # vtable bytes
749            12, 0,  # size of object
750            11, 0,  # start of value 0
751            10, 0,  # start of value 1
752            9, 0,  # start of value 2
753            8, 0,  # start of value 3
754            7, 0,  # start of value 4
755            6, 0,  # start of value 5
756            5, 0,  # start of value 6
757            4, 0,  # start of value 7
758            20, 0, 0, 0,  # vtable offset
759
760            1,  # value 7
761            1,  # value 6
762            1,  # value 5
763            1,  # value 4
764            1,  # value 3
765            1,  # value 2
766            1,  # value 1
767            1,  # value 0
768        ])
769
770    def test_three_bools(self):
771        b = flatbuffers.Builder(0)
772        b.StartObject(3)
773        b.PrependBoolSlot(0, True, False)
774        b.PrependBoolSlot(1, True, False)
775        b.PrependBoolSlot(2, True, False)
776        off = b.EndObject()
777        b.Finish(off)
778
779        self.assertBuilderEquals(b, [
780            16, 0, 0, 0,  # root of table: points to vtable offset
781
782            0, 0,  # padding
783
784            10, 0,  # vtable bytes
785            8, 0,  # size of object
786            7, 0,  # start of value 0
787            6, 0,  # start of value 1
788            5, 0,  # start of value 2
789            10, 0, 0, 0,  # vtable offset from here
790
791            0,  # padding
792            1,  # value 2
793            1,  # value 1
794            1,  # value 0
795        ])
796
797    def test_some_floats(self):
798        b = flatbuffers.Builder(0)
799        b.StartObject(1)
800        b.PrependFloat32Slot(0, 1.0, 0.0)
801        off = b.EndObject()
802
803        self.assertBuilderEquals(b, [
804            6, 0,  # vtable bytes
805            8, 0,  # size of object
806            4, 0,  # start of value 0
807            6, 0, 0, 0,  # vtable offset
808
809            0, 0, 128, 63,  # value 0
810        ])
811
812
813def make_monster_from_generated_code():
814    ''' Use generated code to build the example Monster. '''
815
816    b = flatbuffers.Builder(0)
817    string = b.CreateString("MyMonster")
818    test1 = b.CreateString("test1")
819    test2 = b.CreateString("test2")
820    fred = b.CreateString("Fred")
821
822    MyGame.Example.Monster.MonsterStartInventoryVector(b, 5)
823    b.PrependByte(4)
824    b.PrependByte(3)
825    b.PrependByte(2)
826    b.PrependByte(1)
827    b.PrependByte(0)
828    inv = b.EndVector(5)
829
830    MyGame.Example.Monster.MonsterStart(b)
831    MyGame.Example.Monster.MonsterAddName(b, fred)
832    mon2 = MyGame.Example.Monster.MonsterEnd(b)
833
834    MyGame.Example.Monster.MonsterStartTest4Vector(b, 2)
835    MyGame.Example.Test.CreateTest(b, 10, 20)
836    MyGame.Example.Test.CreateTest(b, 30, 40)
837    test4 = b.EndVector(2)
838
839    MyGame.Example.Monster.MonsterStartTestarrayofstringVector(b, 2)
840    b.PrependUOffsetTRelative(test2)
841    b.PrependUOffsetTRelative(test1)
842    testArrayOfString = b.EndVector(2)
843
844    MyGame.Example.Monster.MonsterStartVectorOfLongsVector(b, 5)
845    b.PrependInt64(100000000)
846    b.PrependInt64(1000000)
847    b.PrependInt64(10000)
848    b.PrependInt64(100)
849    b.PrependInt64(1)
850    VectorOfLongs = b.EndVector(5)
851
852    MyGame.Example.Monster.MonsterStartVectorOfDoublesVector(b, 3)
853    b.PrependFloat64(1.7976931348623157e+308)
854    b.PrependFloat64(0)
855    b.PrependFloat64(-1.7976931348623157e+308)
856    VectorOfDoubles = b.EndVector(3)
857
858    MyGame.Example.Monster.MonsterStart(b)
859
860    pos = MyGame.Example.Vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
861    MyGame.Example.Monster.MonsterAddPos(b, pos)
862
863    MyGame.Example.Monster.MonsterAddHp(b, 80)
864    MyGame.Example.Monster.MonsterAddName(b, string)
865    MyGame.Example.Monster.MonsterAddInventory(b, inv)
866    MyGame.Example.Monster.MonsterAddTestType(b, 1)
867    MyGame.Example.Monster.MonsterAddTest(b, mon2)
868    MyGame.Example.Monster.MonsterAddTest4(b, test4)
869    MyGame.Example.Monster.MonsterAddTestarrayofstring(b, testArrayOfString)
870    MyGame.Example.Monster.MonsterAddVectorOfLongs(b, VectorOfLongs)
871    MyGame.Example.Monster.MonsterAddVectorOfDoubles(b, VectorOfDoubles)
872    mon = MyGame.Example.Monster.MonsterEnd(b)
873
874    b.Finish(mon)
875
876    return b.Bytes, b.Head()
877
878
879class TestAllCodePathsOfExampleSchema(unittest.TestCase):
880    def setUp(self, *args, **kwargs):
881        super(TestAllCodePathsOfExampleSchema, self).setUp(*args, **kwargs)
882
883        b = flatbuffers.Builder(0)
884        MyGame.Example.Monster.MonsterStart(b)
885        gen_mon = MyGame.Example.Monster.MonsterEnd(b)
886        b.Finish(gen_mon)
887
888        self.mon = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
889                                                                   b.Head())
890
891    def test_default_monster_pos(self):
892        self.assertTrue(self.mon.Pos() is None)
893
894    def test_nondefault_monster_mana(self):
895        b = flatbuffers.Builder(0)
896        MyGame.Example.Monster.MonsterStart(b)
897        MyGame.Example.Monster.MonsterAddMana(b, 50)
898        mon = MyGame.Example.Monster.MonsterEnd(b)
899        b.Finish(mon)
900
901        got_mon = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
902                                                                  b.Head())
903        self.assertEqual(50, got_mon.Mana())
904
905    def test_default_monster_hp(self):
906        self.assertEqual(100, self.mon.Hp())
907
908    def test_default_monster_name(self):
909        self.assertEqual(b'', self.mon.Name())
910
911    def test_default_monster_inventory_item(self):
912        self.assertEqual(0, self.mon.Inventory(0))
913
914    def test_default_monster_inventory_length(self):
915        self.assertEqual(0, self.mon.InventoryLength())
916
917    def test_default_monster_color(self):
918        self.assertEqual(MyGame.Example.Color.Color.Blue, self.mon.Color())
919
920    def test_nondefault_monster_color(self):
921        b = flatbuffers.Builder(0)
922        color = MyGame.Example.Color.Color.Red
923        MyGame.Example.Monster.MonsterStart(b)
924        MyGame.Example.Monster.MonsterAddColor(b, color)
925        mon = MyGame.Example.Monster.MonsterEnd(b)
926        b.Finish(mon)
927
928        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
929                                                               b.Head())
930        self.assertEqual(MyGame.Example.Color.Color.Red, mon2.Color())
931
932    def test_default_monster_testtype(self):
933        self.assertEqual(0, self.mon.TestType())
934
935    def test_default_monster_test_field(self):
936        self.assertEqual(None, self.mon.Test())
937
938    def test_default_monster_test4_item(self):
939        self.assertEqual(None, self.mon.Test4(0))
940
941    def test_default_monster_test4_length(self):
942        self.assertEqual(0, self.mon.Test4Length())
943
944    def test_default_monster_testarrayofstring(self):
945        self.assertEqual("", self.mon.Testarrayofstring(0))
946
947    def test_default_monster_testarrayofstring_length(self):
948        self.assertEqual(0, self.mon.TestarrayofstringLength())
949
950    def test_default_monster_testarrayoftables(self):
951        self.assertEqual(None, self.mon.Testarrayoftables(0))
952
953    def test_nondefault_monster_testarrayoftables(self):
954        b = flatbuffers.Builder(0)
955
956        # make a child Monster within a vector of Monsters:
957        MyGame.Example.Monster.MonsterStart(b)
958        MyGame.Example.Monster.MonsterAddHp(b, 99)
959        sub_monster = MyGame.Example.Monster.MonsterEnd(b)
960
961        # build the vector:
962        MyGame.Example.Monster.MonsterStartTestarrayoftablesVector(b, 1)
963        b.PrependUOffsetTRelative(sub_monster)
964        vec = b.EndVector(1)
965
966        # make the parent monster and include the vector of Monster:
967        MyGame.Example.Monster.MonsterStart(b)
968        MyGame.Example.Monster.MonsterAddTestarrayoftables(b, vec)
969        mon = MyGame.Example.Monster.MonsterEnd(b)
970        b.Finish(mon)
971
972        # inspect the resulting data:
973        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Output(), 0)
974        self.assertEqual(99, mon2.Testarrayoftables(0).Hp())
975        self.assertEqual(1, mon2.TestarrayoftablesLength())
976
977    def test_default_monster_testarrayoftables_length(self):
978        self.assertEqual(0, self.mon.TestarrayoftablesLength())
979
980    def test_nondefault_monster_enemy(self):
981        b = flatbuffers.Builder(0)
982
983        # make an Enemy object:
984        MyGame.Example.Monster.MonsterStart(b)
985        MyGame.Example.Monster.MonsterAddHp(b, 88)
986        enemy = MyGame.Example.Monster.MonsterEnd(b)
987        b.Finish(enemy)
988
989        # make the parent monster and include the vector of Monster:
990        MyGame.Example.Monster.MonsterStart(b)
991        MyGame.Example.Monster.MonsterAddEnemy(b, enemy)
992        mon = MyGame.Example.Monster.MonsterEnd(b)
993        b.Finish(mon)
994
995        # inspect the resulting data:
996        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
997                                                               b.Head())
998        self.assertEqual(88, mon2.Enemy().Hp())
999
1000    def test_default_monster_testnestedflatbuffer(self):
1001        self.assertEqual(0, self.mon.Testnestedflatbuffer(0))
1002
1003    def test_default_monster_testnestedflatbuffer_length(self):
1004        self.assertEqual(0, self.mon.TestnestedflatbufferLength())
1005
1006    def test_nondefault_monster_testnestedflatbuffer(self):
1007        b = flatbuffers.Builder(0)
1008
1009        MyGame.Example.Monster.MonsterStartTestnestedflatbufferVector(b, 3)
1010        b.PrependByte(4)
1011        b.PrependByte(2)
1012        b.PrependByte(0)
1013        sub_buf = b.EndVector(3)
1014
1015        # make the parent monster and include the vector of Monster:
1016        MyGame.Example.Monster.MonsterStart(b)
1017        MyGame.Example.Monster.MonsterAddTestnestedflatbuffer(b, sub_buf)
1018        mon = MyGame.Example.Monster.MonsterEnd(b)
1019        b.Finish(mon)
1020
1021        # inspect the resulting data:
1022        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
1023                                                               b.Head())
1024        self.assertEqual(3, mon2.TestnestedflatbufferLength())
1025        self.assertEqual(0, mon2.Testnestedflatbuffer(0))
1026        self.assertEqual(2, mon2.Testnestedflatbuffer(1))
1027        self.assertEqual(4, mon2.Testnestedflatbuffer(2))
1028        try:
1029            imp.find_module('numpy')
1030            # if numpy exists, then we should be able to get the
1031            # vector as a numpy array
1032            self.assertEqual([0, 2, 4], mon2.TestnestedflatbufferAsNumpy().tolist())
1033        except ImportError:
1034            assertRaises(self,
1035                         lambda: mon2.TestnestedflatbufferAsNumpy(),
1036                         NumpyRequiredForThisFeature)
1037
1038    def test_nondefault_monster_testempty(self):
1039        b = flatbuffers.Builder(0)
1040
1041        # make a Stat object:
1042        MyGame.Example.Stat.StatStart(b)
1043        MyGame.Example.Stat.StatAddVal(b, 123)
1044        my_stat = MyGame.Example.Stat.StatEnd(b)
1045        b.Finish(my_stat)
1046
1047        # include the stat object in a monster:
1048        MyGame.Example.Monster.MonsterStart(b)
1049        MyGame.Example.Monster.MonsterAddTestempty(b, my_stat)
1050        mon = MyGame.Example.Monster.MonsterEnd(b)
1051        b.Finish(mon)
1052
1053        # inspect the resulting data:
1054        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
1055                                                               b.Head())
1056        self.assertEqual(123, mon2.Testempty().Val())
1057
1058    def test_default_monster_testbool(self):
1059        self.assertFalse(self.mon.Testbool())
1060
1061    def test_nondefault_monster_testbool(self):
1062        b = flatbuffers.Builder(0)
1063        MyGame.Example.Monster.MonsterStart(b)
1064        MyGame.Example.Monster.MonsterAddTestbool(b, True)
1065        mon = MyGame.Example.Monster.MonsterEnd(b)
1066        b.Finish(mon)
1067
1068        # inspect the resulting data:
1069        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
1070                                                               b.Head())
1071        self.assertTrue(mon2.Testbool())
1072
1073    def test_default_monster_testhashes(self):
1074        self.assertEqual(0, self.mon.Testhashs32Fnv1())
1075        self.assertEqual(0, self.mon.Testhashu32Fnv1())
1076        self.assertEqual(0, self.mon.Testhashs64Fnv1())
1077        self.assertEqual(0, self.mon.Testhashu64Fnv1())
1078        self.assertEqual(0, self.mon.Testhashs32Fnv1a())
1079        self.assertEqual(0, self.mon.Testhashu32Fnv1a())
1080        self.assertEqual(0, self.mon.Testhashs64Fnv1a())
1081        self.assertEqual(0, self.mon.Testhashu64Fnv1a())
1082
1083    def test_nondefault_monster_testhashes(self):
1084        b = flatbuffers.Builder(0)
1085        MyGame.Example.Monster.MonsterStart(b)
1086        MyGame.Example.Monster.MonsterAddTesthashs32Fnv1(b, 1)
1087        MyGame.Example.Monster.MonsterAddTesthashu32Fnv1(b, 2)
1088        MyGame.Example.Monster.MonsterAddTesthashs64Fnv1(b, 3)
1089        MyGame.Example.Monster.MonsterAddTesthashu64Fnv1(b, 4)
1090        MyGame.Example.Monster.MonsterAddTesthashs32Fnv1a(b, 5)
1091        MyGame.Example.Monster.MonsterAddTesthashu32Fnv1a(b, 6)
1092        MyGame.Example.Monster.MonsterAddTesthashs64Fnv1a(b, 7)
1093        MyGame.Example.Monster.MonsterAddTesthashu64Fnv1a(b, 8)
1094        mon = MyGame.Example.Monster.MonsterEnd(b)
1095        b.Finish(mon)
1096
1097        # inspect the resulting data:
1098        mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
1099                                                               b.Head())
1100        self.assertEqual(1, mon2.Testhashs32Fnv1())
1101        self.assertEqual(2, mon2.Testhashu32Fnv1())
1102        self.assertEqual(3, mon2.Testhashs64Fnv1())
1103        self.assertEqual(4, mon2.Testhashu64Fnv1())
1104        self.assertEqual(5, mon2.Testhashs32Fnv1a())
1105        self.assertEqual(6, mon2.Testhashu32Fnv1a())
1106        self.assertEqual(7, mon2.Testhashs64Fnv1a())
1107        self.assertEqual(8, mon2.Testhashu64Fnv1a())
1108
1109    def test_getrootas_for_nonroot_table(self):
1110        b = flatbuffers.Builder(0)
1111        string = b.CreateString("MyStat")
1112
1113        MyGame.Example.Stat.StatStart(b)
1114        MyGame.Example.Stat.StatAddId(b, string)
1115        MyGame.Example.Stat.StatAddVal(b, 12345678)
1116        MyGame.Example.Stat.StatAddCount(b, 12345)
1117        stat = MyGame.Example.Stat.StatEnd(b)
1118        b.Finish(stat)
1119
1120        stat2 = MyGame.Example.Stat.Stat.GetRootAsStat(b.Bytes, b.Head())
1121
1122        self.assertEqual(b"MyStat", stat2.Id())
1123        self.assertEqual(12345678, stat2.Val())
1124        self.assertEqual(12345, stat2.Count())
1125
1126
1127class TestVtableDeduplication(unittest.TestCase):
1128    ''' TestVtableDeduplication verifies that vtables are deduplicated. '''
1129
1130    def test_vtable_deduplication(self):
1131        b = flatbuffers.Builder(0)
1132
1133        b.StartObject(4)
1134        b.PrependByteSlot(0, 0, 0)
1135        b.PrependByteSlot(1, 11, 0)
1136        b.PrependByteSlot(2, 22, 0)
1137        b.PrependInt16Slot(3, 33, 0)
1138        obj0 = b.EndObject()
1139
1140        b.StartObject(4)
1141        b.PrependByteSlot(0, 0, 0)
1142        b.PrependByteSlot(1, 44, 0)
1143        b.PrependByteSlot(2, 55, 0)
1144        b.PrependInt16Slot(3, 66, 0)
1145        obj1 = b.EndObject()
1146
1147        b.StartObject(4)
1148        b.PrependByteSlot(0, 0, 0)
1149        b.PrependByteSlot(1, 77, 0)
1150        b.PrependByteSlot(2, 88, 0)
1151        b.PrependInt16Slot(3, 99, 0)
1152        obj2 = b.EndObject()
1153
1154        got = b.Bytes[b.Head():]
1155
1156        want = bytearray([
1157            240, 255, 255, 255,  # == -12. offset to dedupped vtable.
1158            99, 0,
1159            88,
1160            77,
1161            248, 255, 255, 255,  # == -8. offset to dedupped vtable.
1162            66, 0,
1163            55,
1164            44,
1165            12, 0,
1166            8, 0,
1167            0, 0,
1168            7, 0,
1169            6, 0,
1170            4, 0,
1171            12, 0, 0, 0,
1172            33, 0,
1173            22,
1174            11,
1175        ])
1176
1177        self.assertEqual((len(want), want), (len(got), got))
1178
1179        table0 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj0)
1180        table1 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj1)
1181        table2 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj2)
1182
1183        def _checkTable(tab, voffsett_value, b, c, d):
1184            # vtable size
1185            got = tab.GetVOffsetTSlot(0, 0)
1186            self.assertEqual(12, got, 'case 0, 0')
1187
1188            # object size
1189            got = tab.GetVOffsetTSlot(2, 0)
1190            self.assertEqual(8, got, 'case 2, 0')
1191
1192            # default value
1193            got = tab.GetVOffsetTSlot(4, 0)
1194            self.assertEqual(voffsett_value, got, 'case 4, 0')
1195
1196            got = tab.GetSlot(6, 0, N.Uint8Flags)
1197            self.assertEqual(b, got, 'case 6, 0')
1198
1199            val = tab.GetSlot(8, 0, N.Uint8Flags)
1200            self.assertEqual(c, val, 'failed 8, 0')
1201
1202            got = tab.GetSlot(10, 0, N.Uint8Flags)
1203            self.assertEqual(d, got, 'failed 10, 0')
1204
1205        _checkTable(table0, 0, 11, 22, 33)
1206        _checkTable(table1, 0, 44, 55, 66)
1207        _checkTable(table2, 0, 77, 88, 99)
1208
1209
1210class TestExceptions(unittest.TestCase):
1211    def test_object_is_nested_error(self):
1212        b = flatbuffers.Builder(0)
1213        b.StartObject(0)
1214        assertRaises(self, lambda: b.StartObject(0),
1215                     flatbuffers.builder.IsNestedError)
1216
1217    def test_object_is_not_nested_error(self):
1218        b = flatbuffers.Builder(0)
1219        assertRaises(self, lambda: b.EndObject(),
1220                     flatbuffers.builder.IsNotNestedError)
1221
1222    def test_struct_is_not_inline_error(self):
1223        b = flatbuffers.Builder(0)
1224        b.StartObject(0)
1225        assertRaises(self, lambda: b.PrependStructSlot(0, 1, 0),
1226                     flatbuffers.builder.StructIsNotInlineError)
1227
1228    def test_unreachable_error(self):
1229        b = flatbuffers.Builder(0)
1230        assertRaises(self, lambda: b.PrependUOffsetTRelative(1),
1231                     flatbuffers.builder.OffsetArithmeticError)
1232
1233    def test_create_string_is_nested_error(self):
1234        b = flatbuffers.Builder(0)
1235        b.StartObject(0)
1236        s = 'test1'
1237        assertRaises(self, lambda: b.CreateString(s),
1238                     flatbuffers.builder.IsNestedError)
1239
1240    def test_create_byte_vector_is_nested_error(self):
1241        b = flatbuffers.Builder(0)
1242        b.StartObject(0)
1243        s = b'test1'
1244        assertRaises(self, lambda: b.CreateByteVector(s),
1245                     flatbuffers.builder.IsNestedError)
1246
1247    def test_finished_bytes_error(self):
1248        b = flatbuffers.Builder(0)
1249        assertRaises(self, lambda: b.Output(),
1250                     flatbuffers.builder.BuilderNotFinishedError)
1251
1252
1253def CheckAgainstGoldDataGo():
1254    try:
1255        gen_buf, gen_off = make_monster_from_generated_code()
1256        fn = 'monsterdata_go_wire.mon'
1257        if not os.path.exists(fn):
1258            print('Go-generated data does not exist, failed.')
1259            return False
1260
1261        # would like to use a context manager here, but it's less
1262        # backwards-compatible:
1263        f = open(fn, 'rb')
1264        go_wire_data = f.read()
1265        f.close()
1266
1267        CheckReadBuffer(bytearray(go_wire_data), 0)
1268        if not bytearray(gen_buf[gen_off:]) == bytearray(go_wire_data):
1269            raise AssertionError('CheckAgainstGoldDataGo failed')
1270    except:
1271        print('Failed to test against Go-generated test data.')
1272        return False
1273
1274    print('Can read Go-generated test data, and Python generates bytewise identical data.')
1275    return True
1276
1277
1278def CheckAgainstGoldDataJava():
1279    try:
1280        gen_buf, gen_off = make_monster_from_generated_code()
1281        fn = 'monsterdata_java_wire.mon'
1282        if not os.path.exists(fn):
1283            print('Java-generated data does not exist, failed.')
1284            return False
1285        f = open(fn, 'rb')
1286        java_wire_data = f.read()
1287        f.close()
1288
1289        CheckReadBuffer(bytearray(java_wire_data), 0)
1290    except:
1291        print('Failed to read Java-generated test data.')
1292        return False
1293
1294    print('Can read Java-generated test data.')
1295    return True
1296
1297
1298class LCG(object):
1299    ''' Include simple random number generator to ensure results will be the
1300        same cross platform.
1301        http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator '''
1302
1303    __slots__ = ['n']
1304
1305    InitialLCGSeed = 48271
1306
1307    def __init__(self):
1308        self.n = self.InitialLCGSeed
1309
1310    def Reset(self):
1311        self.n = self.InitialLCGSeed
1312
1313    def Next(self):
1314        self.n = ((self.n * 279470273) % 4294967291) & 0xFFFFFFFF
1315        return self.n
1316
1317
1318def BenchmarkVtableDeduplication(count):
1319    '''
1320    BenchmarkVtableDeduplication measures the speed of vtable deduplication
1321    by creating `prePop` vtables, then populating `count` objects with a
1322    different single vtable.
1323
1324    When count is large (as in long benchmarks), memory usage may be high.
1325    '''
1326
1327    prePop = 10
1328    builder = flatbuffers.Builder(0)
1329
1330    # pre-populate some vtables:
1331    for i in compat_range(prePop):
1332        builder.StartObject(i)
1333        for j in compat_range(i):
1334            builder.PrependInt16Slot(j, j, 0)
1335        builder.EndObject()
1336
1337    # benchmark deduplication of a new vtable:
1338    def f():
1339        builder.StartObject(prePop)
1340        for j in compat_range(prePop):
1341            builder.PrependInt16Slot(j, j, 0)
1342        builder.EndObject()
1343
1344    duration = timeit.timeit(stmt=f, number=count)
1345    rate = float(count) / duration
1346    print(('vtable deduplication rate: %.2f/sec' % rate))
1347
1348
1349def BenchmarkCheckReadBuffer(count, buf, off):
1350    '''
1351    BenchmarkCheckReadBuffer measures the speed of flatbuffer reading
1352    by re-using the CheckReadBuffer function with the gold data.
1353    '''
1354
1355    def f():
1356        CheckReadBuffer(buf, off)
1357
1358    duration = timeit.timeit(stmt=f, number=count)
1359    rate = float(count) / duration
1360    data = float(len(buf) * count) / float(1024 * 1024)
1361    data_rate = data / float(duration)
1362
1363    print(('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/sec, %.2fMB/sec')
1364          % (count, len(buf), duration, rate, data_rate))
1365
1366
1367def BenchmarkMakeMonsterFromGeneratedCode(count, length):
1368    '''
1369    BenchmarkMakeMonsterFromGeneratedCode measures the speed of flatbuffer
1370    creation by re-using the make_monster_from_generated_code function for
1371    generating gold data examples.
1372    '''
1373
1374    duration = timeit.timeit(stmt=make_monster_from_generated_code,
1375                             number=count)
1376    rate = float(count) / duration
1377    data = float(length * count) / float(1024 * 1024)
1378    data_rate = data / float(duration)
1379
1380    print(('built %d %d-byte flatbuffers in %.2fsec: %.2f/sec, %.2fMB/sec' % \
1381           (count, length, duration, rate, data_rate)))
1382
1383
1384def backward_compatible_run_tests(**kwargs):
1385    if PY_VERSION < (2, 6):
1386        sys.stderr.write("Python version less than 2.6 are not supported")
1387        sys.stderr.flush()
1388        return False
1389
1390    # python2.6 has a reduced-functionality unittest.main function:
1391    if PY_VERSION == (2, 6):
1392        try:
1393            unittest.main(**kwargs)
1394        except SystemExit as e:
1395            if not e.code == 0:
1396                return False
1397        return True
1398
1399    # python2.7 and above let us not exit once unittest.main is run:
1400    kwargs['exit'] = False
1401    kwargs['verbosity'] = 0
1402    ret = unittest.main(**kwargs)
1403    if ret.result.errors or ret.result.failures:
1404        return False
1405
1406    return True
1407
1408def main():
1409    import os
1410    import sys
1411    if not len(sys.argv) == 4:
1412       sys.stderr.write('Usage: %s <benchmark vtable count>'
1413                        '<benchmark read count> <benchmark build count>\n'
1414                        % sys.argv[0])
1415       sys.stderr.write('       Provide COMPARE_GENERATED_TO_GO=1   to check'
1416                        'for bytewise comparison to Go data.\n')
1417       sys.stderr.write('       Provide COMPARE_GENERATED_TO_JAVA=1 to check'
1418                        'for bytewise comparison to Java data.\n')
1419       sys.stderr.flush()
1420       sys.exit(1)
1421
1422    kwargs = dict(argv=sys.argv[:-3])
1423
1424    # run tests, and run some language comparison checks if needed:
1425    success = backward_compatible_run_tests(**kwargs)
1426    if success and os.environ.get('COMPARE_GENERATED_TO_GO', 0) == "1":
1427        success = success and CheckAgainstGoldDataGo()
1428    if success and os.environ.get('COMPARE_GENERATED_TO_JAVA', 0) == "1":
1429        success = success and CheckAgainstGoldDataJava()
1430
1431    if not success:
1432        sys.stderr.write('Tests failed, skipping benchmarks.\n')
1433        sys.stderr.flush()
1434        sys.exit(1)
1435
1436    # run benchmarks (if 0, they will be a noop):
1437    bench_vtable = int(sys.argv[1])
1438    bench_traverse = int(sys.argv[2])
1439    bench_build = int(sys.argv[3])
1440    if bench_vtable:
1441        BenchmarkVtableDeduplication(bench_vtable)
1442    if bench_traverse:
1443        buf, off = make_monster_from_generated_code()
1444        BenchmarkCheckReadBuffer(bench_traverse, buf, off)
1445    if bench_build:
1446        buf, off = make_monster_from_generated_code()
1447        BenchmarkMakeMonsterFromGeneratedCode(bench_build, len(buf))
1448
1449if __name__ == '__main__':
1450    main()
1451