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