...

Text file src/github.com/google/flatbuffers/dart/test/flat_buffers_test.dart

Documentation: github.com/google/flatbuffers/dart/test

     1import 'dart:typed_data';
     2import 'dart:io' as io;
     3
     4import 'package:path/path.dart' as path;
     5
     6import 'package:flat_buffers/flat_buffers.dart';
     7import 'package:test/test.dart';
     8import 'package:test_reflective_loader/test_reflective_loader.dart';
     9
    10import './monster_test_my_game.example_generated.dart' as example;
    11import './monster_test_my_game.example2_generated.dart' as example2;
    12import './list_of_enums_generated.dart' as example3;
    13import './bool_structs_generated.dart' as example4;
    14import './keyword_test_keyword_test_generated.dart' as keyword_test;
    15
    16main() {
    17  defineReflectiveSuite(() {
    18    defineReflectiveTests(BuilderTest);
    19    defineReflectiveTests(ObjectAPITest);
    20    defineReflectiveTests(CheckOtherLangaugesData);
    21    defineReflectiveTests(GeneratorTest);
    22    defineReflectiveTests(ListOfEnumsTest);
    23  });
    24}
    25
    26int indexToField(int index) {
    27  return (1 + 1 + index) * 2;
    28}
    29
    30@reflectiveTest
    31class CheckOtherLangaugesData {
    32  test_cppData() async {
    33    List<int> data = await io.File(path.join(
    34      path.context.current,
    35      'test',
    36      'monsterdata_test.mon',
    37    )).readAsBytes();
    38    example.Monster mon = example.Monster(data);
    39    expect(mon.hp, 80);
    40    expect(mon.mana, 150);
    41    expect(mon.name, 'MyMonster');
    42    expect(mon.pos!.x, 1.0);
    43    expect(mon.pos!.y, 2.0);
    44    expect(mon.pos!.z, 3.0);
    45    expect(mon.pos!.test1, 3.0);
    46    expect(mon.pos!.test2.value, 2.0);
    47    expect(mon.pos!.test3.a, 5);
    48    expect(mon.pos!.test3.b, 6);
    49    expect(mon.testType!.value, example.AnyTypeId.Monster.value);
    50    expect(mon.test is example.Monster, true);
    51    final monster2 = mon.test as example.Monster;
    52    expect(monster2.name, "Fred");
    53
    54    expect(mon.inventory!.length, 5);
    55    expect(mon.inventory!.reduce((cur, next) => cur + next), 10);
    56    final test4 = mon.test4!;
    57    expect(test4.length, 2);
    58    expect(test4[0].a + test4[0].b + test4[1].a + test4[1].b, 100);
    59    expect(mon.testarrayofstring!.length, 2);
    60    expect(mon.testarrayofstring![0], "test1");
    61    expect(mon.testarrayofstring![1], "test2");
    62
    63    // this will fail if accessing any field fails.
    64    expect(
    65      mon.toString(),
    66      'Monster{'
    67      'pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, '
    68      'mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], '
    69      'color: Color{value: 8}, testType: AnyTypeId{value: 1}, '
    70      'test: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
    71      'inventory: null, color: Color{value: 8}, testType: null, '
    72      'test: null, test4: null, testarrayofstring: null, '
    73      'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
    74      'testempty: null, testbool: false, testhashs32Fnv1: 0, '
    75      'testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, '
    76      'testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, '
    77      'testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, '
    78      'testf2: 3.0, testf3: 0.0, testarrayofstring2: null, '
    79      'testarrayofsortedstruct: null, flex: null, test5: null, '
    80      'vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, '
    81      'vectorOfReferrables: null, singleWeakReference: 0, '
    82      'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
    83      'coOwningReference: 0, vectorOfCoOwningReferences: null, '
    84      'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
    85      'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
    86      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
    87      'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
    88      'nativeInline: null, '
    89      'longEnumNonEnumDefault: LongEnum{value: 0}, '
    90      'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
    91      'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
    92      'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
    93      '-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}, '
    94      'test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
    95      'testarrayofstring: [test1, test2], testarrayoftables: null, '
    96      'enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
    97      'inventory: null, color: Color{value: 8}, testType: null, '
    98      'test: null, test4: null, testarrayofstring: null, '
    99      'testarrayoftables: null, enemy: null, testnestedflatbuffer: null, '
   100      'testempty: null, testbool: false, testhashs32Fnv1: 0, '
   101      'testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, '
   102      'testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, '
   103      'testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, '
   104      'testf2: 3.0, testf3: 0.0, testarrayofstring2: null, '
   105      'testarrayofsortedstruct: null, flex: null, test5: null, '
   106      'vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, '
   107      'vectorOfReferrables: null, singleWeakReference: 0, '
   108      'vectorOfWeakReferences: null, vectorOfStrongReferrables: null, '
   109      'coOwningReference: 0, vectorOfCoOwningReferences: null, '
   110      'nonOwningReference: 0, vectorOfNonOwningReferences: null, '
   111      'anyUniqueType: null, anyUnique: null, anyAmbiguousType: null, '
   112      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
   113      'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
   114      'nativeInline: null, '
   115      'longEnumNonEnumDefault: LongEnum{value: 0}, '
   116      'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
   117      'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
   118      'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
   119      '-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}, '
   120      'testnestedflatbuffer: null, testempty: null, testbool: true, '
   121      'testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, '
   122      'testhashs64Fnv1: 7930699090847568257, '
   123      'testhashu64Fnv1: 7930699090847568257, '
   124      'testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, '
   125      'testhashs64Fnv1a: 4898026182817603057, '
   126      'testhashu64Fnv1a: 4898026182817603057, '
   127      'testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, '
   128      'testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: ['
   129      'Ability{id: 0, distance: 45}, Ability{id: 1, distance: 21}, '
   130      'Ability{id: 5, distance: 12}], '
   131      'flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
   132      'vectorOfLongs: [1, 100, 10000, 1000000, 100000000], '
   133      'vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], '
   134      'parentNamespaceTest: null, vectorOfReferrables: null, '
   135      'singleWeakReference: 0, vectorOfWeakReferences: null, '
   136      'vectorOfStrongReferrables: null, coOwningReference: 0, '
   137      'vectorOfCoOwningReferences: null, nonOwningReference: 0, '
   138      'vectorOfNonOwningReferences: null, '
   139      'anyUniqueType: null, anyUnique: null, '
   140      'anyAmbiguousType: null, '
   141      'anyAmbiguous: null, vectorOfEnums: null, signedEnum: Race{value: -1}, '
   142      'testrequirednestedflatbuffer: null, scalarKeySortedTables: [Stat{id: '
   143      'miss, val: 0, count: 0}, Stat{id: hit, val: 10, count: 1}], '
   144      'nativeInline: Test{a: 1, b: 2}, '
   145      'longEnumNonEnumDefault: LongEnum{value: 0}, '
   146      'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
   147      'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
   148      'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
   149      '-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}'
   150    );
   151  }
   152}
   153
   154/// Test a custom, fixed-memory allocator (no actual allocations performed)
   155class CustomAllocator extends Allocator {
   156  final _memory = ByteData(10 * 1024);
   157  int _used = 0;
   158
   159  Uint8List buffer(int size) => _memory.buffer.asUint8List(_used - size, size);
   160
   161  @override
   162  ByteData allocate(int size) {
   163    if (size > _memory.lengthInBytes) {
   164      throw UnsupportedError('Trying to allocate too much');
   165    }
   166    _used = size;
   167    return ByteData.sublistView(_memory, 0, size);
   168  }
   169
   170  @override
   171  void deallocate(ByteData _) {}
   172}
   173
   174@reflectiveTest
   175class BuilderTest {
   176  void test_monsterBuilder([Builder? builder]) {
   177    final fbBuilder = builder ?? Builder();
   178    final str = fbBuilder.writeString('MyMonster');
   179
   180    fbBuilder.writeString('test1');
   181    fbBuilder.writeString('test2', asciiOptimization: true);
   182    final testArrayOfString = fbBuilder.endStructVector(2);
   183
   184    final fred = fbBuilder.writeString('Fred');
   185
   186    final List<int> treasure = [0, 1, 2, 3, 4];
   187    final inventory = fbBuilder.writeListUint8(treasure);
   188
   189    final monBuilder = example.MonsterBuilder(fbBuilder)
   190      ..begin()
   191      ..addNameOffset(fred);
   192    final mon2 = monBuilder.finish();
   193
   194    final testBuilder = example.TestBuilder(fbBuilder);
   195    testBuilder.finish(10, 20);
   196    testBuilder.finish(30, 40);
   197    final test4 = fbBuilder.endStructVector(2);
   198
   199    monBuilder
   200      ..begin()
   201      ..addPos(
   202        example.Vec3Builder(fbBuilder).finish(
   203          1.0,
   204          2.0,
   205          3.0,
   206          3.0,
   207          example.Color.Green,
   208          () => testBuilder.finish(5, 6),
   209        ),
   210      )
   211      ..addHp(80)
   212      ..addNameOffset(str)
   213      ..addInventoryOffset(inventory)
   214      ..addTestType(example.AnyTypeId.Monster)
   215      ..addTestOffset(mon2)
   216      ..addTest4Offset(test4)
   217      ..addTestarrayofstringOffset(testArrayOfString);
   218    final mon = monBuilder.finish();
   219    fbBuilder.finish(mon);
   220  }
   221
   222  void test_error_addInt32_withoutStartTable([Builder? builder]) {
   223    builder ??= Builder();
   224    expect(() {
   225      builder!.addInt32(0, 0);
   226    }, throwsA(isA<AssertionError>()));
   227  }
   228
   229  void test_error_addOffset_withoutStartTable() {
   230    Builder builder = Builder();
   231    expect(() {
   232      builder.addOffset(0, 0);
   233    }, throwsA(isA<AssertionError>()));
   234  }
   235
   236  void test_error_endTable_withoutStartTable() {
   237    Builder builder = Builder();
   238    expect(() {
   239      builder.endTable();
   240    }, throwsA(isA<AssertionError>()));
   241  }
   242
   243  void test_error_startTable_duringTable() {
   244    Builder builder = Builder();
   245    builder.startTable(0);
   246    expect(() {
   247      builder.startTable(0);
   248    }, throwsA(isA<AssertionError>()));
   249  }
   250
   251  void test_error_writeString_duringTable() {
   252    Builder builder = Builder();
   253    builder.startTable(1);
   254    expect(() {
   255      builder.writeString('12345');
   256    }, throwsA(isA<AssertionError>()));
   257  }
   258
   259  void test_file_identifier() {
   260    Uint8List byteList;
   261    {
   262      Builder builder = Builder(initialSize: 0);
   263      builder.startTable(0);
   264      int offset = builder.endTable();
   265      builder.finish(offset, 'Az~ÿ');
   266      byteList = builder.buffer;
   267    }
   268    // Convert byteList to a ByteData so that we can read data from it.
   269    ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
   270    // First 4 bytes are an offset to the table data.
   271    int tableDataLoc = byteData.getUint32(0, Endian.little);
   272    // Next 4 bytes are the file identifier.
   273    expect(byteData.getUint8(4), 65); // 'a'
   274    expect(byteData.getUint8(5), 122); // 'z'
   275    expect(byteData.getUint8(6), 126); // '~'
   276    expect(byteData.getUint8(7), 255); // 'ÿ'
   277    // First 4 bytes of the table data are a backwards offset to the vtable.
   278    int vTableLoc =
   279        tableDataLoc - byteData.getInt32(tableDataLoc, Endian.little);
   280    // First 2 bytes of the vtable are the size of the vtable in bytes, which
   281    // should be 4.
   282    expect(byteData.getUint16(vTableLoc, Endian.little), 4);
   283    // Next 2 bytes are the size of the object in bytes (including the vtable
   284    // pointer), which should be 4.
   285    expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
   286  }
   287
   288  void test_low() {
   289    final allocator = CustomAllocator();
   290    final builder = Builder(initialSize: 0, allocator: allocator);
   291
   292    builder.putUint8(1);
   293    expect(allocator.buffer(builder.size()), [1]);
   294
   295    builder.putUint32(2);
   296    expect(allocator.buffer(builder.size()), [2, 0, 0, 0, 0, 0, 0, 1]);
   297
   298    builder.putUint8(3);
   299    expect(
   300        allocator.buffer(builder.size()), [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
   301
   302    builder.putUint8(4);
   303    expect(
   304        allocator.buffer(builder.size()), [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
   305
   306    builder.putUint8(5);
   307    expect(
   308        allocator.buffer(builder.size()), [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
   309
   310    builder.putUint32(6);
   311    expect(allocator.buffer(builder.size()),
   312        [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
   313  }
   314
   315  void test_table_default() {
   316    List<int> byteList;
   317    {
   318      final builder = Builder(initialSize: 0, allocator: CustomAllocator());
   319      builder.startTable(2);
   320      builder.addInt32(0, 10, 10);
   321      builder.addInt32(1, 20, 10);
   322      int offset = builder.endTable();
   323      builder.finish(offset);
   324      byteList = builder.buffer;
   325      expect(builder.size(), byteList.length);
   326    }
   327    // read and verify
   328    BufferContext buffer = BufferContext.fromBytes(byteList);
   329    int objectOffset = buffer.derefObject(0);
   330    // was not written, so uses the new default value
   331    expect(
   332        const Int32Reader()
   333            .vTableGet(buffer, objectOffset, indexToField(0), 15),
   334        15);
   335    // has the written value
   336    expect(
   337        const Int32Reader()
   338            .vTableGet(buffer, objectOffset, indexToField(1), 15),
   339        20);
   340  }
   341
   342  void test_table_format([Builder? builder]) {
   343    Uint8List byteList;
   344    {
   345      builder ??= Builder(initialSize: 0);
   346      builder.startTable(3);
   347      builder.addInt32(0, 10);
   348      builder.addInt32(1, 20);
   349      builder.addInt32(2, 30);
   350      builder.finish(builder.endTable());
   351      byteList = builder.buffer;
   352    }
   353    // Convert byteList to a ByteData so that we can read data from it.
   354    ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
   355    // First 4 bytes are an offset to the table data.
   356    int tableDataLoc = byteData.getUint32(0, Endian.little);
   357    // First 4 bytes of the table data are a backwards offset to the vtable.
   358    int vTableLoc =
   359        tableDataLoc - byteData.getInt32(tableDataLoc, Endian.little);
   360    // First 2 bytes of the vtable are the size of the vtable in bytes, which
   361    // should be 10.
   362    expect(byteData.getUint16(vTableLoc, Endian.little), 10);
   363    // Next 2 bytes are the size of the object in bytes (including the vtable
   364    // pointer), which should be 16.
   365    expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
   366    // Remaining 6 bytes are the offsets within the object where the ints are
   367    // located.
   368    for (int i = 0; i < 3; i++) {
   369      int offset = byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
   370      expect(
   371          byteData.getInt32(tableDataLoc + offset, Endian.little), 10 + 10 * i);
   372    }
   373  }
   374
   375  void test_table_string() {
   376    String latinString = 'test';
   377    String unicodeString = 'Проба пера';
   378    List<int> byteList;
   379    {
   380      Builder builder = Builder(initialSize: 0);
   381      int? latinStringOffset =
   382          builder.writeString(latinString, asciiOptimization: true);
   383      int? unicodeStringOffset =
   384          builder.writeString(unicodeString, asciiOptimization: true);
   385      builder.startTable(2);
   386      builder.addOffset(0, latinStringOffset);
   387      builder.addOffset(1, unicodeStringOffset);
   388      int offset = builder.endTable();
   389      builder.finish(offset);
   390      byteList = builder.buffer;
   391    }
   392    // read and verify
   393    BufferContext buf = BufferContext.fromBytes(byteList);
   394    int objectOffset = buf.derefObject(0);
   395    expect(
   396        const StringReader()
   397            .vTableGetNullable(buf, objectOffset, indexToField(0)),
   398        latinString);
   399    expect(
   400        const StringReader(asciiOptimization: true)
   401            .vTableGetNullable(buf, objectOffset, indexToField(1)),
   402        unicodeString);
   403  }
   404
   405  void test_table_types([Builder? builder]) {
   406    List<int> byteList;
   407    {
   408      builder ??= Builder(initialSize: 0);
   409      int? stringOffset = builder.writeString('12345');
   410      builder.startTable(7);
   411      builder.addBool(0, true);
   412      builder.addInt8(1, 10);
   413      builder.addInt32(2, 20);
   414      builder.addOffset(3, stringOffset);
   415      builder.addInt32(4, 40);
   416      builder.addUint32(5, 0x9ABCDEF0);
   417      builder.addUint8(6, 0x9A);
   418      int offset = builder.endTable();
   419      builder.finish(offset);
   420      byteList = builder.buffer;
   421    }
   422    // read and verify
   423    BufferContext buf = BufferContext.fromBytes(byteList);
   424    int objectOffset = buf.derefObject(0);
   425    expect(
   426        const BoolReader()
   427            .vTableGetNullable(buf, objectOffset, indexToField(0)),
   428        true);
   429    expect(
   430        const Int8Reader()
   431            .vTableGetNullable(buf, objectOffset, indexToField(1)),
   432        10);
   433    expect(
   434        const Int32Reader()
   435            .vTableGetNullable(buf, objectOffset, indexToField(2)),
   436        20);
   437    expect(
   438        const StringReader()
   439            .vTableGetNullable(buf, objectOffset, indexToField(3)),
   440        '12345');
   441    expect(
   442        const Int32Reader()
   443            .vTableGetNullable(buf, objectOffset, indexToField(4)),
   444        40);
   445    expect(
   446        const Uint32Reader()
   447            .vTableGetNullable(buf, objectOffset, indexToField(5)),
   448        0x9ABCDEF0);
   449    expect(
   450        const Uint8Reader()
   451            .vTableGetNullable(buf, objectOffset, indexToField(6)),
   452        0x9A);
   453  }
   454
   455  void test_writeList_of_Uint32() {
   456    List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
   457    // write
   458    List<int> byteList;
   459    {
   460      Builder builder = Builder(initialSize: 0);
   461      int offset = builder.writeListUint32(values);
   462      builder.finish(offset);
   463      byteList = builder.buffer;
   464    }
   465    // read and verify
   466    BufferContext buf = BufferContext.fromBytes(byteList);
   467    List<int> items = const Uint32ListReader().read(buf, 0);
   468    expect(items, hasLength(4));
   469    expect(items, orderedEquals(values));
   470  }
   471
   472  void test_writeList_ofBool() {
   473    void verifyListBooleans(int len, List<int> trueBits) {
   474      // write
   475      List<int> byteList;
   476      {
   477        Builder builder = Builder(initialSize: 0);
   478        List<bool> values = List<bool>.filled(len, false);
   479        for (int bit in trueBits) {
   480          values[bit] = true;
   481        }
   482        int offset = builder.writeListBool(values);
   483        builder.finish(offset);
   484        byteList = builder.buffer;
   485      }
   486      // read and verify
   487      BufferContext buf = BufferContext.fromBytes(byteList);
   488      List<bool> items = const BoolListReader().read(buf, 0);
   489      expect(items, hasLength(len));
   490      for (int i = 0; i < items.length; i++) {
   491        expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
   492      }
   493    }
   494
   495    verifyListBooleans(0, <int>[]);
   496    verifyListBooleans(1, <int>[]);
   497    verifyListBooleans(1, <int>[0]);
   498    verifyListBooleans(31, <int>[0, 1]);
   499    verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
   500    verifyListBooleans(31, <int>[0, 30]);
   501    verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
   502    verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
   503    verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
   504    verifyListBooleans(63, <int>[]);
   505    verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
   506    verifyListBooleans(63, List<int>.generate(63, (i) => i));
   507    verifyListBooleans(64, <int>[]);
   508    verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
   509    verifyListBooleans(64, <int>[1, 2, 62]);
   510    verifyListBooleans(64, <int>[0, 1, 2, 63]);
   511    verifyListBooleans(64, List<int>.generate(64, (i) => i));
   512    verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
   513  }
   514
   515  void test_writeList_ofInt32() {
   516    List<int> byteList;
   517    {
   518      Builder builder = Builder(initialSize: 0);
   519      int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
   520      builder.finish(offset);
   521      byteList = builder.buffer;
   522    }
   523    // read and verify
   524    BufferContext buf = BufferContext.fromBytes(byteList);
   525    List<int> items = const ListReader<int>(Int32Reader()).read(buf, 0);
   526    expect(items, hasLength(5));
   527    expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
   528  }
   529
   530  void test_writeList_ofFloat64() {
   531    List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
   532    // write
   533    List<int> byteList;
   534    {
   535      Builder builder = Builder(initialSize: 0);
   536      int offset = builder.writeListFloat64(values);
   537      builder.finish(offset);
   538      byteList = builder.buffer;
   539    }
   540
   541    // read and verify
   542    BufferContext buf = BufferContext.fromBytes(byteList);
   543    List<double> items = const Float64ListReader().read(buf, 0);
   544
   545    expect(items, hasLength(values.length));
   546    for (int i = 0; i < values.length; i++) {
   547      expect(values[i], closeTo(items[i], .001));
   548    }
   549  }
   550
   551  void test_writeList_ofFloat32() {
   552    List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
   553    // write
   554    List<int> byteList;
   555    {
   556      Builder builder = Builder(initialSize: 0);
   557      int offset = builder.writeListFloat32(values);
   558      builder.finish(offset);
   559      byteList = builder.buffer;
   560    }
   561    // read and verify
   562    BufferContext buf = BufferContext.fromBytes(byteList);
   563    List<double> items = const Float32ListReader().read(buf, 0);
   564    expect(items, hasLength(5));
   565    for (int i = 0; i < values.length; i++) {
   566      expect(values[i], closeTo(items[i], .001));
   567    }
   568  }
   569
   570  void test_writeList_ofObjects([Builder? builder]) {
   571    List<int> byteList;
   572    {
   573      builder ??= Builder(initialSize: 0);
   574      // write the object #1
   575      int object1;
   576      {
   577        builder.startTable(2);
   578        builder.addInt32(0, 10);
   579        builder.addInt32(1, 20);
   580        object1 = builder.endTable();
   581      }
   582      // write the object #1
   583      int object2;
   584      {
   585        builder.startTable(2);
   586        builder.addInt32(0, 100);
   587        builder.addInt32(1, 200);
   588        object2 = builder.endTable();
   589      }
   590      // write the list
   591      int offset = builder.writeList([object1, object2]);
   592      builder.finish(offset);
   593      byteList = builder.buffer;
   594    }
   595    // read and verify
   596    BufferContext buf = BufferContext.fromBytes(byteList);
   597    List<TestPointImpl> items =
   598        const ListReader<TestPointImpl>(TestPointReader()).read(buf, 0);
   599    expect(items, hasLength(2));
   600    expect(items[0].x, 10);
   601    expect(items[0].y, 20);
   602    expect(items[1].x, 100);
   603    expect(items[1].y, 200);
   604  }
   605
   606  void test_writeList_ofStrings_asRoot() {
   607    List<int> byteList;
   608    {
   609      Builder builder = Builder(initialSize: 0);
   610      int? str1 = builder.writeString('12345');
   611      int? str2 = builder.writeString('ABC');
   612      int offset = builder.writeList([str1, str2]);
   613      builder.finish(offset);
   614      byteList = builder.buffer;
   615    }
   616    // read and verify
   617    BufferContext buf = BufferContext.fromBytes(byteList);
   618    List<String> items = const ListReader<String>(StringReader()).read(buf, 0);
   619    expect(items, hasLength(2));
   620    expect(items, contains('12345'));
   621    expect(items, contains('ABC'));
   622  }
   623
   624  void test_writeList_ofStrings_inObject([Builder? builder]) {
   625    List<int> byteList;
   626    {
   627      builder ??= Builder(initialSize: 0);
   628      int listOffset = builder.writeList(
   629          [builder.writeString('12345'), builder.writeString('ABC')]);
   630      builder.startTable(1);
   631      builder.addOffset(0, listOffset);
   632      int offset = builder.endTable();
   633      builder.finish(offset);
   634      byteList = builder.buffer;
   635    }
   636    // read and verify
   637    BufferContext buf = BufferContext.fromBytes(byteList);
   638    StringListWrapperImpl reader = StringListWrapperReader().read(buf, 0);
   639    List<String>? items = reader.items;
   640    expect(items, hasLength(2));
   641    expect(items, contains('12345'));
   642    expect(items, contains('ABC'));
   643  }
   644
   645  void test_writeList_ofUint32() {
   646    List<int> byteList;
   647    {
   648      Builder builder = Builder(initialSize: 0);
   649      int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
   650      builder.finish(offset);
   651      byteList = builder.buffer;
   652    }
   653    // read and verify
   654    BufferContext buf = BufferContext.fromBytes(byteList);
   655    List<int> items = const Uint32ListReader().read(buf, 0);
   656    expect(items, hasLength(3));
   657    expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
   658  }
   659
   660  void test_writeList_ofUint16() {
   661    List<int> byteList;
   662    {
   663      Builder builder = Builder(initialSize: 0);
   664      int offset = builder.writeListUint16(<int>[1, 2, 60000]);
   665      builder.finish(offset);
   666      byteList = builder.buffer;
   667    }
   668    // read and verify
   669    BufferContext buf = BufferContext.fromBytes(byteList);
   670    List<int> items = const Uint16ListReader().read(buf, 0);
   671    expect(items, hasLength(3));
   672    expect(items, orderedEquals(<int>[1, 2, 60000]));
   673  }
   674
   675  void test_writeList_ofUint8() {
   676    List<int> byteList;
   677    {
   678      Builder builder = Builder(initialSize: 0);
   679      int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A, 0xFA]);
   680      builder.finish(offset);
   681      byteList = builder.buffer;
   682    }
   683    // read and verify
   684    BufferContext buf = BufferContext.fromBytes(byteList);
   685    const buffOffset = 8; // 32-bit offset to the list, + 32-bit length
   686    for (final lazy in [true, false]) {
   687      List<int> items = Uint8ListReader(lazy: lazy).read(buf, 0);
   688      expect(items, hasLength(6));
   689      expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A, 0xFA]));
   690
   691      // overwrite the buffer to verify the laziness
   692      buf.buffer.setUint8(buffOffset + 1, 99);
   693      expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, 0x9A, 0xFA]));
   694
   695      // restore the previous value for the next loop
   696      buf.buffer.setUint8(buffOffset + 1, 2);
   697    }
   698  }
   699
   700  void test_reset() {
   701    // We'll run a selection of tests , reusing the builder between them.
   702    final testCases = <void Function(Builder?)>[
   703      test_monsterBuilder,
   704      test_error_addInt32_withoutStartTable,
   705      test_table_format,
   706      test_table_types,
   707      test_writeList_ofObjects,
   708      test_writeList_ofStrings_inObject
   709    ];
   710
   711    // Execute all test cases in all permutations of their order.
   712    // To do that, we generate permutations of test case indexes.
   713    final testCasesPermutations =
   714        _permutationsOf(List.generate(testCases.length, (index) => index));
   715    expect(testCasesPermutations.length, _factorial(testCases.length));
   716
   717    for (var indexes in testCasesPermutations) {
   718      // print the order so failures are reproducible
   719      printOnFailure('Running reset() test cases in order: $indexes');
   720
   721      Builder? builder;
   722      for (var index in indexes) {
   723        if (builder == null) {
   724          // Initial size small enough so at least one test case increases it.
   725          // On the other hand, it's large enough so that some test cases don't.
   726          builder = Builder(initialSize: 32);
   727        } else {
   728          builder.reset();
   729        }
   730        testCases[index](builder);
   731      }
   732    }
   733  }
   734
   735  // Generate permutations of the given list
   736  List<List<T>> _permutationsOf<T>(List<T> source) {
   737    final result = <List<T>>[];
   738
   739    void permutate(List<T> items, int startAt) {
   740      for (var i = startAt; i < items.length; i++) {
   741        List<T> permutation = items.toList(growable: false);
   742        permutation[i] = items[startAt];
   743        permutation[startAt] = items[i];
   744
   745        // add the current list upon reaching the end
   746        if (startAt == items.length - 1) {
   747          result.add(items);
   748        } else {
   749          permutate(permutation, startAt + 1);
   750        }
   751      }
   752    }
   753
   754    permutate(source, 0);
   755    return result;
   756  }
   757
   758  // a very simple implementation of n!
   759  int _factorial(int n) {
   760    var result = 1;
   761    for (var i = 2; i <= n; i++) {
   762      result *= i;
   763    }
   764    return result;
   765  }
   766}
   767
   768@reflectiveTest
   769class ObjectAPITest {
   770  void test_tableStat() {
   771    final object1 = example.StatT(count: 3, id: "foo", val: 4);
   772    expect(object1 is Packable, isTrue);
   773    final fbb = Builder();
   774    fbb.finish(object1.pack(fbb));
   775    final object2 = example.Stat(fbb.buffer).unpack();
   776    expect(object2.count, object1.count);
   777    expect(object2.id, object1.id);
   778    expect(object2.val, object1.val);
   779    expect(object2.toString(), object1.toString());
   780  }
   781
   782  void test_tableMonster() {
   783    final monster = example.MonsterT()
   784      ..pos = example.Vec3T(
   785          x: 1,
   786          y: 2,
   787          z: 3,
   788          test1: 4.0,
   789          test2: example.Color.Red,
   790          test3: example.TestT(a: 1, b: 2))
   791      ..mana = 2
   792      ..name = 'Monstrous'
   793      ..inventory = [24, 42]
   794      ..color = example.Color.Green
   795      // TODO be smarter for unions and automatically set the `type` field?
   796      ..testType = example.AnyTypeId.MyGame_Example2_Monster
   797      ..test = example2.MonsterT()
   798      ..test4 = [example.TestT(a: 3, b: 4), example.TestT(a: 5, b: 6)]
   799      ..testarrayofstring = ["foo", "bar"]
   800      ..testarrayoftables = [example.MonsterT(name: 'Oof')]
   801      ..enemy = example.MonsterT(name: 'Enemy')
   802      ..testarrayofbools = [false, true, false]
   803      ..testf = 42.24
   804      ..testarrayofsortedstruct = [
   805        example.AbilityT(id: 1, distance: 5),
   806        example.AbilityT(id: 3, distance: 7)
   807      ]
   808      ..vectorOfLongs = [5, 6, 7]
   809      ..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2]
   810      ..anyAmbiguousType = example.AnyAmbiguousAliasesTypeId.M2
   811      ..anyAmbiguous = null
   812      ..vectorOfEnums = [example.Color.Blue, example.Color.Green]
   813      ..signedEnum = example.Race.None;
   814
   815    final fbBuilder = Builder();
   816    final offset = monster.pack(fbBuilder);
   817    expect(offset, isNonZero);
   818    fbBuilder.finish(offset);
   819    final data = fbBuilder.buffer;
   820
   821    // TODO currently broken because of struct builder issue, see #6688
   822    // final monster2 = example.Monster(data); // Monster (reader)
   823    // expect(
   824    //     // map Monster => MonsterT, Vec3 => Vec3T, ...
   825    //     monster2.toString().replaceAllMapped(
   826    //         RegExp('([a-zA-z0-9]+){'), (match) => match.group(1) + 'T{'),
   827    //     monster.toString());
   828    //
   829    // final monster3 = monster2.unpack(); // MonsterT
   830    // expect(monster3.toString(), monster.toString());
   831  }
   832
   833  void test_Lists() {
   834    // Ensure unpack() reads lists eagerly by reusing the same builder and
   835    // overwriting data. Why: because standard reader reads lists lazily...
   836    final fbb = Builder();
   837
   838    final object1 = example.TypeAliasesT(v8: [1, 2, 3], vf64: [5, 6]);
   839    fbb.finish(object1.pack(fbb));
   840    final object1Read = example.TypeAliases(fbb.buffer).unpack();
   841
   842    // overwrite the original buffer by writing to the same builder
   843    fbb.reset();
   844    final object2 = example.TypeAliasesT(v8: [7, 8, 9], vf64: [10, 11]);
   845    fbb.finish(object2.pack(fbb));
   846    final object2Read = example.TypeAliases(fbb.buffer).unpack();
   847
   848    // this is fine even with lazy lists:
   849    expect(object2.toString(), object2Read.toString());
   850
   851    // this fails with lazy lists:
   852    expect(object1.toString(), object1Read.toString());
   853
   854    // empty list must be serialized as such (were stored NULL before v2.0)
   855    fbb.reset();
   856    final object3 = example.TypeAliasesT(v8: [], vf64: null);
   857    fbb.finish(object3.pack(fbb));
   858    final object3Read = example.TypeAliases(fbb.buffer).unpack();
   859    expect(object3.toString(), object3Read.toString());
   860  }
   861}
   862
   863class StringListWrapperImpl {
   864  final BufferContext bp;
   865  final int offset;
   866
   867  StringListWrapperImpl(this.bp, this.offset);
   868
   869  List<String>? get items => const ListReader<String>(StringReader())
   870      .vTableGetNullable(bp, offset, indexToField(0));
   871}
   872
   873class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
   874  const StringListWrapperReader();
   875
   876  @override
   877  StringListWrapperImpl createObject(BufferContext object, int offset) {
   878    return StringListWrapperImpl(object, offset);
   879  }
   880}
   881
   882class TestPointImpl {
   883  final BufferContext bp;
   884  final int offset;
   885
   886  TestPointImpl(this.bp, this.offset);
   887
   888  int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
   889
   890  int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
   891}
   892
   893class TestPointReader extends TableReader<TestPointImpl> {
   894  const TestPointReader();
   895
   896  @override
   897  TestPointImpl createObject(BufferContext object, int offset) {
   898    return TestPointImpl(object, offset);
   899  }
   900}
   901
   902@reflectiveTest
   903class GeneratorTest {
   904  void test_constantEnumValues() async {
   905    expect(example.Color.values, same(example.Color.values));
   906    expect(example.Race.values, same(example.Race.values));
   907    expect(example.AnyTypeId.values, same(example.AnyTypeId.values));
   908    expect(example.AnyUniqueAliasesTypeId.values,
   909        same(example.AnyUniqueAliasesTypeId.values));
   910    expect(example.AnyAmbiguousAliasesTypeId.values,
   911        same(example.AnyAmbiguousAliasesTypeId.values));
   912  }
   913}
   914
   915// See #6869
   916@reflectiveTest
   917class ListOfEnumsTest {
   918  void test_listOfEnums() async {
   919    var mytable = example3.MyTableObjectBuilder(options: [
   920      example3.OptionsEnum.A,
   921      example3.OptionsEnum.B,
   922      example3.OptionsEnum.C
   923    ]);
   924    var bytes = mytable.toBytes();
   925    var mytable_read = example3.MyTable(bytes);
   926    expect(mytable_read.options![0].value, example3.OptionsEnum.A.value);
   927    expect(mytable_read.options![1].value, example3.OptionsEnum.B.value);
   928    expect(mytable_read.options![2].value, example3.OptionsEnum.C.value);
   929  }
   930}
   931
   932@reflectiveTest
   933class BoolInStructTest {
   934  void test_boolInStruct() async {
   935    var mystruct = example4.FooObjectBuilder(
   936        myFoo: example4.FooPropertiesObjectBuilder(a: true, b: false));
   937    var bytes = mystruct.toBytes();
   938    var mystruct_read = example4.Foo(bytes);
   939    expect(mystruct_read.myFoo!.a, true);
   940    expect(mystruct_read.myFoo!.b, false);
   941  }
   942}

View as plain text