1// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5import 'dart:typed_data';
6import 'dart:io' as io;
7
8import 'package:path/path.dart' as path;
9
10import 'package:flat_buffers/flat_buffers.dart';
11import 'package:test/test.dart';
12import 'package:test_reflective_loader/test_reflective_loader.dart';
13
14import './monster_test_my_game.example_generated.dart' as example;
15
16main() {
17  defineReflectiveSuite(() {
18    defineReflectiveTests(BuilderTest);
19    defineReflectiveTests(CheckOtherLangaugesData);
20  });
21}
22
23int indexToField(int index) {
24  return (1 + 1 + index) * 2;
25}
26
27@reflectiveTest
28class CheckOtherLangaugesData {
29  test_cppData() async {
30    List<int> data = await new io.File(path.join(
31      path.dirname(io.Platform.script.path),
32      'monsterdata_test.mon',
33    ))
34        .readAsBytes();
35    example.Monster mon = new example.Monster(data);
36    expect(mon.hp, 80);
37    expect(mon.mana, 150);
38    expect(mon.name, 'MyMonster');
39    expect(mon.pos.x, 1.0);
40    expect(mon.pos.y, 2.0);
41    expect(mon.pos.z, 3.0);
42    expect(mon.pos.test1, 3.0);
43    expect(mon.pos.test2.value, 2.0);
44    expect(mon.pos.test3.a, 5);
45    expect(mon.pos.test3.b, 6);
46    expect(mon.testType.value, example.AnyTypeId.Monster.value);
47    expect(mon.test is example.Monster, true);
48    final monster2 = mon.test as example.Monster;
49    expect(monster2.name, "Fred");
50
51    expect(mon.inventory.length, 5);
52    expect(mon.inventory.reduce((cur, next) => cur + next), 10);
53    expect(mon.test4.length, 2);
54    expect(
55        mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
56    expect(mon.testarrayofstring.length, 2);
57    expect(mon.testarrayofstring[0], "test1");
58    expect(mon.testarrayofstring[1], "test2");
59
60    // this will fail if accessing any field fails.
61    expect(mon.toString(),
62        'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}');
63  }
64}
65
66@reflectiveTest
67class BuilderTest {
68  void test_monsterBuilder() {
69    final fbBuilder = new Builder();
70    final str = fbBuilder.writeString('MyMonster');
71
72    fbBuilder.writeString('test1');
73    fbBuilder.writeString('test2');
74    final testArrayOfString = fbBuilder.endStructVector(2);
75
76    final fred = fbBuilder.writeString('Fred');
77
78    final List<int> treasure = [0, 1, 2, 3, 4];
79    final inventory = fbBuilder.writeListUint8(treasure);
80
81    final monBuilder = new example.MonsterBuilder(fbBuilder)
82      ..begin()
83      ..addNameOffset(fred);
84    final mon2 = monBuilder.finish();
85
86    final testBuilder = new example.TestBuilder(fbBuilder);
87    testBuilder.finish(10, 20);
88    testBuilder.finish(30, 40);
89    final test4 = fbBuilder.endStructVector(2);
90
91
92    monBuilder
93      ..begin()
94      ..addPos(
95        new example.Vec3Builder(fbBuilder).finish(
96          1.0,
97          2.0,
98          3.0,
99          3.0,
100          example.Color.Green,
101          () => testBuilder.finish(5, 6),
102        ),
103      )
104      ..addHp(80)
105      ..addNameOffset(str)
106      ..addInventoryOffset(inventory)
107      ..addTestType(example.AnyTypeId.Monster)
108      ..addTestOffset(mon2)
109      ..addTest4Offset(test4)
110      ..addTestarrayofstringOffset(testArrayOfString);
111    final mon = monBuilder.finish();
112    fbBuilder.finish(mon);
113  }
114
115  void test_error_addInt32_withoutStartTable() {
116    Builder builder = new Builder();
117    expect(() {
118      builder.addInt32(0, 0);
119    }, throwsStateError);
120  }
121
122  void test_error_addOffset_withoutStartTable() {
123    Builder builder = new Builder();
124    expect(() {
125      builder.addOffset(0, 0);
126    }, throwsStateError);
127  }
128
129  void test_error_endTable_withoutStartTable() {
130    Builder builder = new Builder();
131    expect(() {
132      builder.endTable();
133    }, throwsStateError);
134  }
135
136  void test_error_startTable_duringTable() {
137    Builder builder = new Builder();
138    builder.startTable();
139    expect(() {
140      builder.startTable();
141    }, throwsStateError);
142  }
143
144  void test_error_writeString_duringTable() {
145    Builder builder = new Builder();
146    builder.startTable();
147    expect(() {
148      builder.writeString('12345');
149    }, throwsStateError);
150  }
151
152  void test_file_identifier() {
153    Uint8List byteList;
154    {
155      Builder builder = new Builder(initialSize: 0);
156      builder.startTable();
157      int offset = builder.endTable();
158      byteList = builder.finish(offset, 'Az~ÿ');
159    }
160    // Convert byteList to a ByteData so that we can read data from it.
161    ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
162    // First 4 bytes are an offset to the table data.
163    int tableDataLoc = byteData.getUint32(0, Endian.little);
164    // Next 4 bytes are the file identifier.
165    expect(byteData.getUint8(4), 65); // 'a'
166    expect(byteData.getUint8(5), 122); // 'z'
167    expect(byteData.getUint8(6), 126); // '~'
168    expect(byteData.getUint8(7), 255); // 'ÿ'
169    // First 4 bytes of the table data are a backwards offset to the vtable.
170    int vTableLoc = tableDataLoc -
171        byteData.getInt32(tableDataLoc, Endian.little);
172    // First 2 bytes of the vtable are the size of the vtable in bytes, which
173    // should be 4.
174    expect(byteData.getUint16(vTableLoc, Endian.little), 4);
175    // Next 2 bytes are the size of the object in bytes (including the vtable
176    // pointer), which should be 4.
177    expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
178  }
179
180  void test_low() {
181    Builder builder = new Builder(initialSize: 0);
182    expect((builder..putUint8(1)).lowFinish(), [1]);
183    expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
184    expect((builder..putUint8(3)).lowFinish(),
185        [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
186    expect((builder..putUint8(4)).lowFinish(),
187        [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
188    expect((builder..putUint8(5)).lowFinish(),
189        [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
190    expect((builder..putUint32(6)).lowFinish(),
191        [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
192  }
193
194  void test_table_default() {
195    List<int> byteList;
196    {
197      Builder builder = new Builder(initialSize: 0);
198      builder.startTable();
199      builder.addInt32(0, 10, 10);
200      builder.addInt32(1, 20, 10);
201      int offset = builder.endTable();
202      byteList = builder.finish(offset);
203    }
204    // read and verify
205    BufferContext buffer = new BufferContext.fromBytes(byteList);
206    int objectOffset = buffer.derefObject(0);
207    // was not written, so uses the new default value
208    expect(
209        const Int32Reader()
210            .vTableGet(buffer, objectOffset, indexToField(0), 15),
211        15);
212    // has the written value
213    expect(
214        const Int32Reader()
215            .vTableGet(buffer, objectOffset, indexToField(1), 15),
216        20);
217  }
218
219  void test_table_format() {
220    Uint8List byteList;
221    {
222      Builder builder = new Builder(initialSize: 0);
223      builder.startTable();
224      builder.addInt32(0, 10);
225      builder.addInt32(1, 20);
226      builder.addInt32(2, 30);
227      byteList = builder.finish(builder.endTable());
228    }
229    // Convert byteList to a ByteData so that we can read data from it.
230    ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
231    // First 4 bytes are an offset to the table data.
232    int tableDataLoc = byteData.getUint32(0, Endian.little);
233    // First 4 bytes of the table data are a backwards offset to the vtable.
234    int vTableLoc = tableDataLoc -
235        byteData.getInt32(tableDataLoc, Endian.little);
236    // First 2 bytes of the vtable are the size of the vtable in bytes, which
237    // should be 10.
238    expect(byteData.getUint16(vTableLoc, Endian.little), 10);
239    // Next 2 bytes are the size of the object in bytes (including the vtable
240    // pointer), which should be 16.
241    expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
242    // Remaining 6 bytes are the offsets within the object where the ints are
243    // located.
244    for (int i = 0; i < 3; i++) {
245      int offset =
246          byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
247      expect(byteData.getInt32(tableDataLoc + offset, Endian.little),
248          10 + 10 * i);
249    }
250  }
251
252  void test_table_string() {
253    String latinString = 'test';
254    String unicodeString = 'Проба пера';
255    List<int> byteList;
256    {
257      Builder builder = new Builder(initialSize: 0);
258      int latinStringOffset = builder.writeString(latinString);
259      int unicodeStringOffset = builder.writeString(unicodeString);
260      builder.startTable();
261      builder.addOffset(0, latinStringOffset);
262      builder.addOffset(1, unicodeStringOffset);
263      int offset = builder.endTable();
264      byteList = builder.finish(offset);
265    }
266    // read and verify
267    BufferContext buf = new BufferContext.fromBytes(byteList);
268    int objectOffset = buf.derefObject(0);
269    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
270        latinString);
271    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
272        unicodeString);
273  }
274
275  void test_table_types() {
276    List<int> byteList;
277    {
278      Builder builder = new Builder(initialSize: 0);
279      int stringOffset = builder.writeString('12345');
280      builder.startTable();
281      builder.addBool(0, true);
282      builder.addInt8(1, 10);
283      builder.addInt32(2, 20);
284      builder.addOffset(3, stringOffset);
285      builder.addInt32(4, 40);
286      builder.addUint32(5, 0x9ABCDEF0);
287      builder.addUint8(6, 0x9A);
288      int offset = builder.endTable();
289      byteList = builder.finish(offset);
290    }
291    // read and verify
292    BufferContext buf = new BufferContext.fromBytes(byteList);
293    int objectOffset = buf.derefObject(0);
294    expect(
295        const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
296    expect(
297        const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
298    expect(
299        const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
300    expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
301        '12345');
302    expect(
303        const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
304    expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
305        0x9ABCDEF0);
306    expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
307        0x9A);
308  }
309
310  void test_writeList_of_Uint32() {
311    List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
312    // write
313    List<int> byteList;
314    {
315      Builder builder = new Builder(initialSize: 0);
316      int offset = builder.writeListUint32(values);
317      byteList = builder.finish(offset);
318    }
319    // read and verify
320    BufferContext buf = new BufferContext.fromBytes(byteList);
321    List<int> items = const Uint32ListReader().read(buf, 0);
322    expect(items, hasLength(4));
323    expect(items, orderedEquals(values));
324  }
325
326  void test_writeList_ofBool() {
327    void verifyListBooleans(int len, List<int> trueBits) {
328      // write
329      List<int> byteList;
330      {
331        Builder builder = new Builder(initialSize: 0);
332        List<bool> values = new List<bool>.filled(len, false);
333        for (int bit in trueBits) {
334          values[bit] = true;
335        }
336        int offset = builder.writeListBool(values);
337        byteList = builder.finish(offset);
338      }
339      // read and verify
340      BufferContext buf = new BufferContext.fromBytes(byteList);
341      List<bool> items = const BoolListReader().read(buf, 0);
342      expect(items, hasLength(len));
343      for (int i = 0; i < items.length; i++) {
344        expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
345      }
346    }
347
348    verifyListBooleans(0, <int>[]);
349    verifyListBooleans(1, <int>[]);
350    verifyListBooleans(1, <int>[0]);
351    verifyListBooleans(31, <int>[0, 1]);
352    verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
353    verifyListBooleans(31, <int>[0, 30]);
354    verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
355    verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
356    verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
357    verifyListBooleans(63, <int>[]);
358    verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
359    verifyListBooleans(63, new List<int>.generate(63, (i) => i));
360    verifyListBooleans(64, <int>[]);
361    verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
362    verifyListBooleans(64, <int>[1, 2, 62]);
363    verifyListBooleans(64, <int>[0, 1, 2, 63]);
364    verifyListBooleans(64, new List<int>.generate(64, (i) => i));
365    verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
366  }
367
368  void test_writeList_ofInt32() {
369    List<int> byteList;
370    {
371      Builder builder = new Builder(initialSize: 0);
372      int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
373      byteList = builder.finish(offset);
374    }
375    // read and verify
376    BufferContext buf = new BufferContext.fromBytes(byteList);
377    List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
378    expect(items, hasLength(5));
379    expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
380  }
381
382  void test_writeList_ofFloat64() {
383    List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
384    // write
385    List<int> byteList;
386    {
387      Builder builder = new Builder(initialSize: 0);
388      int offset = builder.writeListFloat64(values);
389      byteList = builder.finish(offset);
390    }
391
392    // read and verify
393    BufferContext buf = new BufferContext.fromBytes(byteList);
394    List<double> items = const Float64ListReader().read(buf, 0);
395
396    expect(items, hasLength(values.length));
397    for (int i = 0; i < values.length; i++) {
398      expect(values[i], closeTo(items[i], .001));
399    }
400  }
401
402  void test_writeList_ofFloat32() {
403    List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
404    // write
405    List<int> byteList;
406    {
407      Builder builder = new Builder(initialSize: 0);
408      int offset = builder.writeListFloat32(values);
409      byteList = builder.finish(offset);
410    }
411    // read and verify
412    BufferContext buf = new BufferContext.fromBytes(byteList);
413    List<double> items = const Float32ListReader().read(buf, 0);
414    expect(items, hasLength(5));
415    for (int i = 0; i < values.length; i++) {
416      expect(values[i], closeTo(items[i], .001));
417    }
418  }
419
420  void test_writeList_ofObjects() {
421    List<int> byteList;
422    {
423      Builder builder = new Builder(initialSize: 0);
424      // write the object #1
425      int object1;
426      {
427        builder.startTable();
428        builder.addInt32(0, 10);
429        builder.addInt32(1, 20);
430        object1 = builder.endTable();
431      }
432      // write the object #1
433      int object2;
434      {
435        builder.startTable();
436        builder.addInt32(0, 100);
437        builder.addInt32(1, 200);
438        object2 = builder.endTable();
439      }
440      // write the list
441      int offset = builder.writeList([object1, object2]);
442      byteList = builder.finish(offset);
443    }
444    // read and verify
445    BufferContext buf = new BufferContext.fromBytes(byteList);
446    List<TestPointImpl> items =
447        const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
448    expect(items, hasLength(2));
449    expect(items[0].x, 10);
450    expect(items[0].y, 20);
451    expect(items[1].x, 100);
452    expect(items[1].y, 200);
453  }
454
455  void test_writeList_ofStrings_asRoot() {
456    List<int> byteList;
457    {
458      Builder builder = new Builder(initialSize: 0);
459      int str1 = builder.writeString('12345');
460      int str2 = builder.writeString('ABC');
461      int offset = builder.writeList([str1, str2]);
462      byteList = builder.finish(offset);
463    }
464    // read and verify
465    BufferContext buf = new BufferContext.fromBytes(byteList);
466    List<String> items =
467        const ListReader<String>(const StringReader()).read(buf, 0);
468    expect(items, hasLength(2));
469    expect(items, contains('12345'));
470    expect(items, contains('ABC'));
471  }
472
473  void test_writeList_ofStrings_inObject() {
474    List<int> byteList;
475    {
476      Builder builder = new Builder(initialSize: 0);
477      int listOffset = builder.writeList(
478          [builder.writeString('12345'), builder.writeString('ABC')]);
479      builder.startTable();
480      builder.addOffset(0, listOffset);
481      int offset = builder.endTable();
482      byteList = builder.finish(offset);
483    }
484    // read and verify
485    BufferContext buf = new BufferContext.fromBytes(byteList);
486    StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
487    List<String> items = reader.items;
488    expect(items, hasLength(2));
489    expect(items, contains('12345'));
490    expect(items, contains('ABC'));
491  }
492
493  void test_writeList_ofUint32() {
494    List<int> byteList;
495    {
496      Builder builder = new Builder(initialSize: 0);
497      int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
498      byteList = builder.finish(offset);
499    }
500    // read and verify
501    BufferContext buf = new BufferContext.fromBytes(byteList);
502    List<int> items = const Uint32ListReader().read(buf, 0);
503    expect(items, hasLength(3));
504    expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
505  }
506
507  void test_writeList_ofUint16() {
508    List<int> byteList;
509    {
510      Builder builder = new Builder(initialSize: 0);
511      int offset = builder.writeListUint16(<int>[1, 2, 60000]);
512      byteList = builder.finish(offset);
513    }
514    // read and verify
515    BufferContext buf = new BufferContext.fromBytes(byteList);
516    List<int> items = const Uint16ListReader().read(buf, 0);
517    expect(items, hasLength(3));
518    expect(items, orderedEquals(<int>[1, 2, 60000]));
519  }
520
521  void test_writeList_ofUint8() {
522    List<int> byteList;
523    {
524      Builder builder = new Builder(initialSize: 0);
525      int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
526      byteList = builder.finish(offset);
527    }
528    // read and verify
529    BufferContext buf = new BufferContext.fromBytes(byteList);
530    List<int> items = const Uint8ListReader().read(buf, 0);
531    expect(items, hasLength(5));
532    expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
533  }
534}
535
536class StringListWrapperImpl {
537  final BufferContext bp;
538  final int offset;
539
540  StringListWrapperImpl(this.bp, this.offset);
541
542  List<String> get items => const ListReader<String>(const StringReader())
543      .vTableGet(bp, offset, indexToField(0));
544}
545
546class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
547  const StringListWrapperReader();
548
549  @override
550  StringListWrapperImpl createObject(BufferContext object, int offset) {
551    return new StringListWrapperImpl(object, offset);
552  }
553}
554
555class TestPointImpl {
556  final BufferContext bp;
557  final int offset;
558
559  TestPointImpl(this.bp, this.offset);
560
561  int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
562
563  int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
564}
565
566class TestPointReader extends TableReader<TestPointImpl> {
567  const TestPointReader();
568
569  @override
570  TestPointImpl createObject(BufferContext object, int offset) {
571    return new TestPointImpl(object, offset);
572  }
573}
574