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