1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
|
// Run this using JavaScriptTest.sh
import assert from 'assert'
import fs from 'fs'
import * as flatbuffers from 'flatbuffers'
import { Monster, MonsterT } from './my-game/example/monster.js'
import { Test, TestT } from './my-game/example/test.js'
import { Stat } from './my-game/example/stat.js'
import { Vec3 } from './my-game/example/vec3.js'
import { Color } from './my-game/example/color.js';
import { Any } from './my-game/example/any.js';
function main() {
// First, let's test reading a FlatBuffer generated by C++ code:
// This file was generated from monsterdata_test.json
var data = new Uint8Array(fs.readFileSync('../monsterdata_test.mon'));
// Now test it:
var bb = new flatbuffers.ByteBuffer(data);
testBuffer(bb);
// Second, let's create a FlatBuffer from scratch in JavaScript, and test it also.
// We use an initial size of 1 to exercise the reallocation algorithm,
// normally a size larger than the typical FlatBuffer you generate would be
// better for performance.
var fbb = new flatbuffers.Builder(1);
createMonster(fbb);
serializeAndTest(fbb);
testObjApiPack(fbb);
// clear the builder, repeat tests
var clearIterations = 100;
var startingCapacity = fbb.bb.capacity();
for (var i = 0; i < clearIterations; i++) {
fbb.clear();
createMonster(fbb);
serializeAndTest(fbb);
testObjApiPack(fbb);
}
// the capacity of our buffer shouldn't increase with the same size payload
assert.strictEqual(fbb.bb.capacity(), startingCapacity);
test64bit();
testUnicode();
fuzzTest1();
testNullStrings();
testSharedStrings();
testVectorOfStructs();
testCreateByteVector();
console.log('FlatBuffers test: completed successfully');
}
function createMonster(fbb) {
// We set up the same values as monsterdata.json:
var str = fbb.createString('MyMonster');
var inv = Monster.createInventoryVector(fbb, [0, 1, 2, 3, 4]);
var fred = fbb.createString('Fred');
Monster.startMonster(fbb);
Monster.addName(fbb, fred);
var mon2 = Monster.endMonster(fbb);
Monster.startTest4Vector(fbb, 2);
Test.createTest(fbb, 10, 20);
Test.createTest(fbb, 30, 40);
var test4 = fbb.endVector();
var testArrayOfString = Monster.createTestarrayofstringVector(fbb, [
fbb.createString('test1'),
fbb.createString('test2')
]);
var testVectorOfLongs = Monster.createVectorOfLongsVector(fbb, [
1n,
101010100n
]);
Monster.startMonster(fbb);
Monster.addPos(fbb, Vec3.createVec3(fbb, 1, 2, 3, 3, Color.Green, 5, 6));
Monster.addHp(fbb, 80);
Monster.addName(fbb, str);
Monster.addInventory(fbb, inv);
Monster.addTestType(fbb, Any.Monster);
Monster.addTest(fbb, mon2);
Monster.addTest4(fbb, test4);
Monster.addTestarrayofstring(fbb, testArrayOfString);
Monster.addVectorOfLongs(fbb, testVectorOfLongs);
Monster.addTestbool(fbb, true);
var mon = Monster.endMonster(fbb);
Monster.finishMonsterBuffer(fbb, mon);
}
function serializeAndTest(fbb) {
// Write the result to a file for debugging purposes:
// Note that the binaries are not necessarily identical, since the JSON
// parser may serialize in a slightly different order than the above
// JavaScript code. They are functionally equivalent though.
fs.writeFileSync('monsterdata_javascript_wire.mon', Buffer.from(fbb.asUint8Array()));
// Tests mutation first. This will verify that we did not trample any other
// part of the byte buffer.
testMutation(fbb.dataBuffer());
testBuffer(fbb.dataBuffer());
}
function testMutation(bb) {
var monster = Monster.getRootAsMonster(bb);
monster.mutate_hp(120);
assert.strictEqual(monster.hp(), 120);
monster.mutate_hp(80);
assert.strictEqual(monster.hp(), 80);
var manaRes = monster.mutate_mana(10);
assert.strictEqual(manaRes, false); // Field was NOT present, because default value.
// TODO: There is not the availability to mutate structs or vectors.
}
function testObjApiPack(fbb) {
fbb.clear();
createMonster(fbb);
let monster_t = Monster.getRootAsMonster(fbb.dataBuffer()).unpack();
fbb.clear();
Monster.finishMonsterBuffer(fbb, monster_t.pack(fbb));
serializeAndTest(fbb);
}
function testObjApiUnpack(monster) {
assert.strictEqual(monster.hp, 80);
assert.strictEqual(monster.mana, 150); // default
assert.strictEqual(monster.name, 'MyMonster');
let pos = monster.pos;
assert.strictEqual(pos.x, 1);
assert.strictEqual(pos.y, 2);
assert.strictEqual(pos.z, 3);
assert.strictEqual(pos.test1, 3);
assert.strictEqual(pos.test2, Color.Green);
let test3 = pos.test3;
assert.strictEqual(test3.a, 5);
assert.strictEqual(test3.b, 6);
assert.strictEqual(monster.testType, Any.Monster);
let monster2 = monster.test;
assert.strictEqual(monster2 != null, true);
assert.strictEqual(monster2 instanceof MonsterT, true);
assert.strictEqual(monster2.name, 'Fred');
assert.strictEqual(monster.inventory.length, 5);
let invsum = 0;
for (let i = 0; i < monster.inventory.length; i++) {
invsum += monster.inventory[i];
}
assert.strictEqual(invsum, 10);
let test_0 = monster.test4[0];
let test_1 = monster.test4[1];
assert.strictEqual(monster.test4.length, 2);
assert.strictEqual(test_0.a + test_0.b + test_1.a + test_1.b, 100);
assert.strictEqual(monster.testarrayofstring.length, 2);
assert.strictEqual(monster.testarrayofstring[0], 'test1');
assert.strictEqual(monster.testarrayofstring[1], 'test2');
assert.strictEqual(monster.testbool, true);
}
function testBuffer(bb) {
assert.ok(Monster.bufferHasIdentifier(bb));
var monster = Monster.getRootAsMonster(bb);
assert.strictEqual(monster.hp(), 80);
assert.strictEqual(monster.mana(), 150); // default
assert.strictEqual(monster.name(), 'MyMonster');
var pos = monster.pos();
assert.strictEqual(pos.x(), 1);
assert.strictEqual(pos.y(), 2);
assert.strictEqual(pos.z(), 3);
assert.strictEqual(pos.test1(), 3);
assert.strictEqual(pos.test2(), Color.Green);
var t = pos.test3();
assert.strictEqual(t.a(), 5);
assert.strictEqual(t.b(), 6);
assert.strictEqual(monster.testType(), Any.Monster);
var monster2 = new Monster();
assert.strictEqual(monster.test(monster2) != null, true);
assert.strictEqual(monster2.name(), 'Fred');
assert.strictEqual(monster.inventoryLength(), 5);
var invsum = 0;
for (var i = 0; i < monster.inventoryLength(); i++) {
invsum += monster.inventory(i);
}
assert.strictEqual(invsum, 10);
var invsum2 = 0;
var invArr = monster.inventoryArray();
for (var i = 0; i < invArr.length; i++) {
invsum2 += invArr[i];
}
assert.strictEqual(invsum2, 10);
let longSum = 0n;
for (let idx = 0; idx < monster.vectorOfLongsLength(); ++idx) {
longSum += monster.vectorOfLongs(idx);
}
assert.strictEqual(longSum, 101010101n);
var test_0 = monster.test4(0);
var test_1 = monster.test4(1);
assert.strictEqual(monster.test4Length(), 2);
assert.strictEqual(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
assert.strictEqual(monster.testarrayofstringLength(), 2);
assert.strictEqual(monster.testarrayofstring(0), 'test1');
assert.strictEqual(monster.testarrayofstring(1), 'test2');
assert.strictEqual(monster.testbool(), true);
let monster_t = monster.unpack();
testObjApiUnpack(monster_t);
let monster2_t = new MonsterT();
monster.unpackTo(monster2_t);
testObjApiUnpack(monster2_t);
}
function test64bit() {
var fbb = new flatbuffers.Builder();
var required = fbb.createString('required');
Stat.startStat(fbb);
var stat2 = Stat.endStat(fbb);
Monster.startMonster(fbb);
Monster.addName(fbb, required);
Monster.addTestempty(fbb, stat2);
var mon2 = Monster.endMonster(fbb);
Stat.startStat(fbb);
// 2541551405100253985 = 0x2345678987654321
Stat.addVal(fbb, 0x2345678987654321n);
var stat = Stat.endStat(fbb);
Monster.startMonster(fbb);
Monster.addName(fbb, required);
Monster.addEnemy(fbb, mon2);
Monster.addTestempty(fbb, stat);
var mon = Monster.endMonster(fbb);
Monster.finishMonsterBuffer(fbb, mon);
var bytes = fbb.asUint8Array();
////////////////////////////////////////////////////////////////
var bb = new flatbuffers.ByteBuffer(bytes);
assert.ok(Monster.bufferHasIdentifier(bb));
var mon = Monster.getRootAsMonster(bb);
var stat = mon.testempty();
assert.strictEqual(stat != null, true);
assert.strictEqual(stat.val() != null, true);
assert.strictEqual(stat.val(), 2541551405100253985n);
var mon2 = mon.enemy();
assert.strictEqual(mon2 != null, true);
stat = mon2.testempty();
assert.strictEqual(stat != null, true);
assert.strictEqual(stat.val() != null, true);
assert.strictEqual(stat.val(), 0n); // default value
}
function testUnicode() {
var correct = fs.readFileSync('../unicode_test.mon');
var json = JSON.parse(fs.readFileSync('../unicode_test.json', 'utf8'));
// Test reading
function testReadingUnicode(bb) {
var monster = Monster.getRootAsMonster(bb);
assert.strictEqual(monster.name(), json.name);
assert.deepEqual(Buffer.from(monster.name(flatbuffers.Encoding.UTF8_BYTES)), Buffer.from(json.name));
assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length);
json.testarrayoftables.forEach(function(table, i) {
var value = monster.testarrayoftables(i);
assert.strictEqual(value.name(), table.name);
assert.deepEqual(Buffer.from(value.name(flatbuffers.Encoding.UTF8_BYTES)), Buffer.from(table.name));
});
assert.strictEqual(monster.testarrayofstringLength(), json.testarrayofstring.length);
json.testarrayofstring.forEach(function(string, i) {
assert.strictEqual(monster.testarrayofstring(i), string);
assert.deepEqual(Buffer.from(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), Buffer.from(string));
});
}
testReadingUnicode(new flatbuffers.ByteBuffer(new Uint8Array(correct)));
// Test writing
var fbb = new flatbuffers.Builder();
var name = fbb.createString(json.name);
var testarrayoftablesOffsets = json.testarrayoftables.map(function(table) {
var name = fbb.createString(new Uint8Array(Buffer.from(table.name)));
Monster.startMonster(fbb);
Monster.addName(fbb, name);
return Monster.endMonster(fbb);
});
var testarrayoftablesOffset = Monster.createTestarrayoftablesVector(fbb,
testarrayoftablesOffsets);
var testarrayofstringOffset = Monster.createTestarrayofstringVector(fbb,
json.testarrayofstring.map(function(string) { return fbb.createString(string); }));
Monster.startMonster(fbb);
Monster.addTestarrayofstring(fbb, testarrayofstringOffset);
Monster.addTestarrayoftables(fbb, testarrayoftablesOffset);
Monster.addName(fbb, name);
Monster.finishSizePrefixedMonsterBuffer(fbb, Monster.endMonster(fbb));
var bb = new flatbuffers.ByteBuffer(fbb.asUint8Array())
bb.setPosition(4);
testReadingUnicode(bb);
}
var __imul = Math.imul ? Math.imul : function(a, b) {
var ah = a >> 16 & 65535;
var bh = b >> 16 & 65535;
var al = a & 65535;
var bl = b & 65535;
return al * bl + (ah * bl + al * bh << 16) | 0;
};
// Include simple random number generator to ensure results will be the
// same cross platform.
// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
var lcg_seed = 48271;
function lcg_rand() {
return lcg_seed = (__imul(lcg_seed, 279470273) >>> 0) % 4294967291;
}
function lcg_reset() {
lcg_seed = 48271;
}
// Converts a Field ID to a virtual table offset.
function fieldIndexToOffset(field_id) {
// Should correspond to what EndTable() below builds up.
var fixed_fields = 2; // Vtable size and Object Size.
return (field_id + fixed_fields) * 2;
}
// Low level stress/fuzz test: serialize/deserialize a variety of
// different kinds of data in different combinations
function fuzzTest1() {
// Values we're testing against: chosen to ensure no bits get chopped
// off anywhere, and also be different from eachother.
var bool_val = true;
var char_val = -127; // 0x81
var uchar_val = 0xFF;
var short_val = -32222; // 0x8222;
var ushort_val = 0xFEEE;
var int_val = 0x83333333 | 0;
var uint_val = 0xFDDDDDDD;
var long_val = BigInt.asIntN(64, 0x8444444444444444n);
var ulong_val = BigInt.asUintN(64, 0xFCCCCCCCCCCCCCCCn);
var float_val = new Float32Array([3.14159])[0];
var double_val = 3.14159265359;
var test_values_max = 11;
var fields_per_object = 4;
var num_fuzz_objects = 10000; // The higher, the more thorough :)
var builder = new flatbuffers.Builder();
lcg_reset(); // Keep it deterministic.
var objects = [];
// Generate num_fuzz_objects random objects each consisting of
// fields_per_object fields, each of a random type.
for (var i = 0; i < num_fuzz_objects; i++) {
builder.startObject(fields_per_object);
for (var f = 0; f < fields_per_object; f++) {
var choice = lcg_rand() % test_values_max;
switch (choice) {
case 0: builder.addFieldInt8(f, bool_val, 0); break;
case 1: builder.addFieldInt8(f, char_val, 0); break;
case 2: builder.addFieldInt8(f, uchar_val, 0); break;
case 3: builder.addFieldInt16(f, short_val, 0); break;
case 4: builder.addFieldInt16(f, ushort_val, 0); break;
case 5: builder.addFieldInt32(f, int_val, 0); break;
case 6: builder.addFieldInt32(f, uint_val, 0); break;
case 7: builder.addFieldInt64(f, long_val, 0n); break;
case 8: builder.addFieldInt64(f, ulong_val, 0n); break;
case 9: builder.addFieldFloat32(f, float_val, 0); break;
case 10: builder.addFieldFloat64(f, double_val, 0); break;
}
}
objects.push(builder.endObject());
}
builder.prep(8, 0); // Align whole buffer.
lcg_reset(); // Reset.
builder.finish(objects[objects.length - 1]);
var bytes = new Uint8Array(builder.asUint8Array());
var view = new DataView(bytes.buffer);
// Test that all objects we generated are readable and return the
// expected values. We generate random objects in the same order
// so this is deterministic.
for (var i = 0; i < num_fuzz_objects; i++) {
var offset = bytes.length - objects[i];
for (var f = 0; f < fields_per_object; f++) {
var choice = lcg_rand() % test_values_max;
var vtable_offset = fieldIndexToOffset(f);
var vtable = offset - view.getInt32(offset, true);
assert.ok(vtable_offset < view.getInt16(vtable, true));
var field_offset = offset + view.getInt16(vtable + vtable_offset, true);
switch (choice) {
case 0: assert.strictEqual(!!view.getInt8(field_offset), bool_val); break;
case 1: assert.strictEqual(view.getInt8(field_offset), char_val); break;
case 2: assert.strictEqual(view.getUint8(field_offset), uchar_val); break;
case 3: assert.strictEqual(view.getInt16(field_offset, true), short_val); break;
case 4: assert.strictEqual(view.getUint16(field_offset, true), ushort_val); break;
case 5: assert.strictEqual(view.getInt32(field_offset, true), int_val); break;
case 6: assert.strictEqual(view.getUint32(field_offset, true), uint_val); break;
case 7: assert.strictEqual(view.getBigInt64(field_offset, true), long_val); break;
case 8: assert.strictEqual(view.getBigUint64(field_offset, true), ulong_val); break;
case 9: assert.strictEqual(view.getFloat32(field_offset, true), float_val); break;
case 10: assert.strictEqual(view.getFloat64(field_offset, true), double_val); break;
}
}
}
}
function testSharedStrings() {
var shared_string = "Hello world";
var builder = new flatbuffers.Builder();
let mainOffset = builder.createSharedString(shared_string);
assert.strictEqual(builder.createSharedString(shared_string), mainOffset);
}
function testNullStrings() {
var builder = new flatbuffers.Builder();
assert.strictEqual(builder.createString(null), 0);
assert.strictEqual(builder.createSharedString(null), 0);
assert.strictEqual(builder.createString(undefined), 0);
assert.strictEqual(builder.createSharedString(undefined), 0);
}
function testVectorOfStructs() {
let monster = new MonsterT();
monster.name = 'testVectorOfStructs';
monster.test4 = [
new TestT(1, 2),
new TestT(3, 4)
];
let builder = new flatbuffers.Builder();
builder.finish(monster.pack(builder));
let decodedMonster = Monster.getRootAsMonster(builder.dataBuffer()).unpack();
assert.strictEqual(decodedMonster.test4[0].a, 1);
assert.strictEqual(decodedMonster.test4[0].b, 2);
assert.strictEqual(decodedMonster.test4[1].a, 3);
assert.strictEqual(decodedMonster.test4[1].b, 4);
}
function testCreateByteVector() {
const data = Uint8Array.from([1, 2, 3, 4, 5]);
const builder = new flatbuffers.Builder();
const required = builder.createString("required");
const offset = builder.createByteVector(data);
Monster.startMonster(builder);
Monster.addName(builder, required);
Monster.addInventory(builder, offset)
builder.finish(Monster.endMonster(builder));
let decodedMonster = Monster.getRootAsMonster(builder.dataBuffer());
assert.deepEqual(decodedMonster.inventoryArray(), data);
}
main();
|