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