blob: 65057673994a6dc4c3d4e3dbffc0bf879c113a20 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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 */
16
17import java.io.*;
18import java.nio.ByteBuffer;
19import java.nio.ByteOrder;
20import java.nio.channels.FileChannel;
21import MyGame.Example.*;
22import NamespaceA.*;
23import NamespaceA.NamespaceB.*;
24import com.google.flatbuffers.ByteBufferUtil;
25import static com.google.flatbuffers.Constants.*;
26import com.google.flatbuffers.FlatBufferBuilder;
27import MyGame.MonsterExtra;
28
29class JavaTest {
30 public static void main(String[] args) {
31
32 // First, let's test reading a FlatBuffer generated by C++ code:
33 // This file was generated from monsterdata_test.json
34
35 byte[] data = null;
36 File file = new File("monsterdata_test.mon");
37 RandomAccessFile f = null;
38 try {
39 f = new RandomAccessFile(file, "r");
40 data = new byte[(int)f.length()];
41 f.readFully(data);
42 f.close();
43 } catch(java.io.IOException e) {
44 System.out.println("FlatBuffers test: couldn't read file");
45 return;
46 }
47
48 // Now test it:
49
50 ByteBuffer bb = ByteBuffer.wrap(data);
51 TestBuffer(bb);
52
53 // Second, let's create a FlatBuffer from scratch in Java, and test it also.
54 // We use an initial size of 1 to exercise the reallocation algorithm,
55 // normally a size larger than the typical FlatBuffer you generate would be
56 // better for performance.
57 FlatBufferBuilder fbb = new FlatBufferBuilder(1);
58
59 TestBuilderBasics(fbb, true);
60 TestBuilderBasics(fbb, false);
61
62 TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
63
64 TestNamespaceNesting();
65
66 TestNestedFlatBuffer();
67
68 TestCreateByteVector();
69
70 TestCreateUninitializedVector();
71
72 TestByteBufferFactory();
73
74 TestSizedInputStream();
75
76 TestVectorOfUnions();
77
78 TestFixedLengthArrays();
79
80 System.out.println("FlatBuffers test: completed successfully");
81 }
82
83 static void TestEnums() {
84 TestEq(Color.name(Color.Red), "Red");
85 TestEq(Color.name(Color.Blue), "Blue");
86 TestEq(Any.name(Any.NONE), "NONE");
87 TestEq(Any.name(Any.Monster), "Monster");
88 }
89
90 static void TestBuffer(ByteBuffer bb) {
91 TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
92
93 Monster monster = Monster.getRootAsMonster(bb);
94
95 TestEq(monster.hp(), (short)80);
96 TestEq(monster.mana(), (short)150); // default
97
98 TestEq(monster.name(), "MyMonster");
99 // monster.friendly() // can't access, deprecated
100
101 Vec3 pos = monster.pos();
102 TestEq(pos.x(), 1.0f);
103 TestEq(pos.y(), 2.0f);
104 TestEq(pos.z(), 3.0f);
105 TestEq(pos.test1(), 3.0);
106 // issue: int != byte
107 TestEq(pos.test2(), (int) Color.Green);
108 Test t = pos.test3();
109 TestEq(t.a(), (short)5);
110 TestEq(t.b(), (byte)6);
111
112 TestEq(monster.testType(), (byte)Any.Monster);
113 Monster monster2 = new Monster();
114 TestEq(monster.test(monster2) != null, true);
115 TestEq(monster2.name(), "Fred");
116
117 TestEq(monster.inventoryLength(), 5);
118 int invsum = 0;
119 for (int i = 0; i < monster.inventoryLength(); i++)
120 invsum += monster.inventory(i);
121 TestEq(invsum, 10);
122
123 // Alternative way of accessing a vector:
124 ByteBuffer ibb = monster.inventoryAsByteBuffer();
125 invsum = 0;
126 while (ibb.position() < ibb.limit())
127 invsum += ibb.get();
128 TestEq(invsum, 10);
129
130 Test test_0 = monster.test4(0);
131 Test test_1 = monster.test4(1);
132 TestEq(monster.test4Length(), 2);
133 TestEq(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
134
135 TestEq(monster.testarrayofstringLength(), 2);
136 TestEq(monster.testarrayofstring(0),"test1");
137 TestEq(monster.testarrayofstring(1),"test2");
138
139 TestEq(monster.testbool(), true);
140 }
141
142 // this method checks additional fields not present in the binary buffer read from file
143 // these new tests are performed on top of the regular tests
144 static void TestExtendedBuffer(ByteBuffer bb) {
145 TestBuffer(bb);
146
147 Monster monster = Monster.getRootAsMonster(bb);
148
149 TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
150 }
151
152 static void TestNamespaceNesting() {
153 // reference / manipulate these to verify compilation
154 FlatBufferBuilder fbb = new FlatBufferBuilder(1);
155
156 TableInNestedNS.startTableInNestedNS(fbb);
157 TableInNestedNS.addFoo(fbb, 1234);
158 int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
159
160 TableInFirstNS.startTableInFirstNS(fbb);
161 TableInFirstNS.addFooTable(fbb, nestedTableOff);
162 int off = TableInFirstNS.endTableInFirstNS(fbb);
163 }
164
165 static void TestNestedFlatBuffer() {
166 final String nestedMonsterName = "NestedMonsterName";
167 final short nestedMonsterHp = 600;
168 final short nestedMonsterMana = 1024;
169
170 FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
171 int str1 = fbb1.createString(nestedMonsterName);
172 Monster.startMonster(fbb1);
173 Monster.addName(fbb1, str1);
174 Monster.addHp(fbb1, nestedMonsterHp);
175 Monster.addMana(fbb1, nestedMonsterMana);
176 int monster1 = Monster.endMonster(fbb1);
177 Monster.finishMonsterBuffer(fbb1, monster1);
178 byte[] fbb1Bytes = fbb1.sizedByteArray();
179 fbb1 = null;
180
181 FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
182 int str2 = fbb2.createString("My Monster");
183 int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
184 Monster.startMonster(fbb2);
185 Monster.addName(fbb2, str2);
186 Monster.addHp(fbb2, (short)50);
187 Monster.addMana(fbb2, (short)32);
188 Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
189 int monster = Monster.endMonster(fbb2);
190 Monster.finishMonsterBuffer(fbb2, monster);
191
192 // Now test the data extracted from the nested buffer
193 Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
194 Monster nestedMonster = mons.testnestedflatbufferAsMonster();
195
196 TestEq(nestedMonsterMana, nestedMonster.mana());
197 TestEq(nestedMonsterHp, nestedMonster.hp());
198 TestEq(nestedMonsterName, nestedMonster.name());
199 }
200
201 static void TestCreateByteVector() {
202 FlatBufferBuilder fbb = new FlatBufferBuilder(16);
203 int str = fbb.createString("MyMonster");
204 byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
205 int vec = fbb.createByteVector(inventory);
206 Monster.startMonster(fbb);
207 Monster.addInventory(fbb, vec);
208 Monster.addName(fbb, str);
209 int monster1 = Monster.endMonster(fbb);
210 Monster.finishMonsterBuffer(fbb, monster1);
211 Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
212
213 TestEq(monsterObject.inventory(1), (int)inventory[1]);
214 TestEq(monsterObject.inventoryLength(), inventory.length);
215 TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
216 }
217
218 static void TestCreateUninitializedVector() {
219 FlatBufferBuilder fbb = new FlatBufferBuilder(16);
220 int str = fbb.createString("MyMonster");
221 byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
222 ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1);
223 for (byte i:inventory) {
224 bb.put(i);
225 }
226 int vec = fbb.endVector();
227 Monster.startMonster(fbb);
228 Monster.addInventory(fbb, vec);
229 Monster.addName(fbb, str);
230 int monster1 = Monster.endMonster(fbb);
231 Monster.finishMonsterBuffer(fbb, monster1);
232 Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
233
234 TestEq(monsterObject.inventory(1), (int)inventory[1]);
235 TestEq(monsterObject.inventoryLength(), inventory.length);
236 TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
237 }
238
239 static void TestByteBufferFactory() {
240 final class MappedByteBufferFactory extends FlatBufferBuilder.ByteBufferFactory {
241 @Override
242 public ByteBuffer newByteBuffer(int capacity) {
243 ByteBuffer bb;
244 try {
245 bb = new RandomAccessFile("javatest.bin", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, capacity).order(ByteOrder.LITTLE_ENDIAN);
246 } catch(Throwable e) {
247 System.out.println("FlatBuffers test: couldn't map ByteBuffer to a file");
248 bb = null;
249 }
250 return bb;
251 }
252 }
253
254 FlatBufferBuilder fbb = new FlatBufferBuilder(1, new MappedByteBufferFactory());
255
256 TestBuilderBasics(fbb, false);
257 }
258
259 static void TestSizedInputStream() {
260 // Test on default FlatBufferBuilder that uses HeapByteBuffer
261 FlatBufferBuilder fbb = new FlatBufferBuilder(1);
262
263 TestBuilderBasics(fbb, false);
264
265 InputStream in = fbb.sizedInputStream();
266 byte[] array = fbb.sizedByteArray();
267 int count = 0;
268 int currentVal = 0;
269
270 while (currentVal != -1 && count < array.length) {
271 try {
272 currentVal = in.read();
273 } catch(java.io.IOException e) {
274 System.out.println("FlatBuffers test: couldn't read from InputStream");
275 return;
276 }
277 TestEq((byte)currentVal, array[count]);
278 count++;
279 }
280 TestEq(count, array.length);
281 }
282
283 static void TestBuilderBasics(FlatBufferBuilder fbb, boolean sizePrefix) {
284 int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
285 int[] off = new int[3];
286 Monster.startMonster(fbb);
287 Monster.addName(fbb, names[0]);
288 off[0] = Monster.endMonster(fbb);
289 Monster.startMonster(fbb);
290 Monster.addName(fbb, names[1]);
291 off[1] = Monster.endMonster(fbb);
292 Monster.startMonster(fbb);
293 Monster.addName(fbb, names[2]);
294 off[2] = Monster.endMonster(fbb);
295 int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
296
297 // We set up the same values as monsterdata.json:
298
299 int str = fbb.createString("MyMonster");
300
301 int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
302
303 int fred = fbb.createString("Fred");
304 Monster.startMonster(fbb);
305 Monster.addName(fbb, fred);
306 int mon2 = Monster.endMonster(fbb);
307
308 Monster.startTest4Vector(fbb, 2);
309 Test.createTest(fbb, (short)10, (byte)20);
310 Test.createTest(fbb, (short)30, (byte)40);
311 int test4 = fbb.endVector();
312
313 int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
314 fbb.createString("test1"),
315 fbb.createString("test2")
316 });
317
318 Monster.startMonster(fbb);
319 Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
320 Color.Green, (short)5, (byte)6));
321 Monster.addHp(fbb, (short)80);
322 Monster.addName(fbb, str);
323 Monster.addInventory(fbb, inv);
324 Monster.addTestType(fbb, (byte)Any.Monster);
325 Monster.addTest(fbb, mon2);
326 Monster.addTest4(fbb, test4);
327 Monster.addTestarrayofstring(fbb, testArrayOfString);
328 Monster.addTestbool(fbb, true);
329 Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
330 Monster.addTestarrayoftables(fbb, sortMons);
331 int mon = Monster.endMonster(fbb);
332
333 if (sizePrefix) {
334 Monster.finishSizePrefixedMonsterBuffer(fbb, mon);
335 } else {
336 Monster.finishMonsterBuffer(fbb, mon);
337 }
338
339 // Write the result to a file for debugging purposes:
340 // Note that the binaries are not necessarily identical, since the JSON
341 // parser may serialize in a slightly different order than the above
342 // Java code. They are functionally equivalent though.
343
344 try {
345 String filename = "monsterdata_java_wire" + (sizePrefix ? "_sp" : "") + ".mon";
346 FileChannel fc = new FileOutputStream(filename).getChannel();
347 fc.write(fbb.dataBuffer().duplicate());
348 fc.close();
349 } catch(java.io.IOException e) {
350 System.out.println("FlatBuffers test: couldn't write file");
351 return;
352 }
353
354 // Test it:
355 ByteBuffer dataBuffer = fbb.dataBuffer();
356 if (sizePrefix) {
357 TestEq(ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH,
358 dataBuffer.remaining());
359 dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer);
360 }
361 TestExtendedBuffer(dataBuffer);
362
363 // Make sure it also works with read only ByteBuffers. This is slower,
364 // since creating strings incurs an additional copy
365 // (see Table.__string).
366 TestExtendedBuffer(dataBuffer.asReadOnlyBuffer());
367
368 TestEnums();
369
370 //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
371 // revert to original values after testing
372 Monster monster = Monster.getRootAsMonster(dataBuffer);
373
374 // mana is optional and does not exist in the buffer so the mutation should fail
375 // the mana field should retain its default value
376 TestEq(monster.mutateMana((short)10), false);
377 TestEq(monster.mana(), (short)150);
378
379 // Accessing a vector of sorted by the key tables
380 TestEq(monster.testarrayoftables(0).name(), "Barney");
381 TestEq(monster.testarrayoftables(1).name(), "Frodo");
382 TestEq(monster.testarrayoftables(2).name(), "Wilma");
383
384 // Example of searching for a table by the key
385 TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
386 TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
387 TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
388
389 // testType is an existing field and mutating it should succeed
390 TestEq(monster.testType(), (byte)Any.Monster);
391 TestEq(monster.mutateTestType(Any.NONE), true);
392 TestEq(monster.testType(), (byte)Any.NONE);
393 TestEq(monster.mutateTestType(Any.Monster), true);
394 TestEq(monster.testType(), (byte)Any.Monster);
395
396 //mutate the inventory vector
397 TestEq(monster.mutateInventory(0, 1), true);
398 TestEq(monster.mutateInventory(1, 2), true);
399 TestEq(monster.mutateInventory(2, 3), true);
400 TestEq(monster.mutateInventory(3, 4), true);
401 TestEq(monster.mutateInventory(4, 5), true);
402
403 for (int i = 0; i < monster.inventoryLength(); i++) {
404 TestEq(monster.inventory(i), i + 1);
405 }
406
407 //reverse mutation
408 TestEq(monster.mutateInventory(0, 0), true);
409 TestEq(monster.mutateInventory(1, 1), true);
410 TestEq(monster.mutateInventory(2, 2), true);
411 TestEq(monster.mutateInventory(3, 3), true);
412 TestEq(monster.mutateInventory(4, 4), true);
413
414 // get a struct field and edit one of its fields
415 Vec3 pos = monster.pos();
416 TestEq(pos.x(), 1.0f);
417 pos.mutateX(55.0f);
418 TestEq(pos.x(), 55.0f);
419 pos.mutateX(1.0f);
420 TestEq(pos.x(), 1.0f);
421 }
422
423 static void TestVectorOfUnions() {
424 final FlatBufferBuilder fbb = new FlatBufferBuilder();
425
426 final int swordAttackDamage = 1;
427
428 final int[] characterVector = new int[] {
429 Attacker.createAttacker(fbb, swordAttackDamage),
430 };
431
432 final byte[] characterTypeVector = new byte[]{
433 Character.MuLan,
434 };
435
436 Movie.finishMovieBuffer(
437 fbb,
438 Movie.createMovie(
439 fbb,
440 (byte)0,
441 (byte)0,
442 Movie.createCharactersTypeVector(fbb, characterTypeVector),
443 Movie.createCharactersVector(fbb, characterVector)
444 )
445 );
446
447 final Movie movie = Movie.getRootAsMovie(fbb.dataBuffer());
448
449 TestEq(movie.charactersTypeLength(), characterTypeVector.length);
450 TestEq(movie.charactersLength(), characterVector.length);
451
452 TestEq(movie.charactersType(0), characterTypeVector[0]);
453
454 TestEq(((Attacker)movie.characters(new Attacker(), 0)).swordAttackDamage(), swordAttackDamage);
455 }
456
457 static void TestFixedLengthArrays() {
458 FlatBufferBuilder builder = new FlatBufferBuilder(0);
459
460 float a;
461 int[] b = new int[15];
462 byte c;
463 int[][] d_a = new int[2][2];
464 byte[] d_b = new byte[2];
465 byte[][] d_c = new byte[2][2];
466
467 a = 0.5f;
468 for (int i = 0; i < 15; i++) b[i] = i;
469 c = 1;
470 d_a[0][0] = 1;
471 d_a[0][1] = 2;
472 d_a[1][0] = 3;
473 d_a[1][1] = 4;
474 d_b[0] = TestEnum.B;
475 d_b[1] = TestEnum.C;
476 d_c[0][0] = TestEnum.A;
477 d_c[0][1] = TestEnum.B;
478 d_c[1][0] = TestEnum.C;
479 d_c[1][1] = TestEnum.B;
480
481 int arrayOffset = ArrayStruct.createArrayStruct(builder,
482 a, b, c, d_a, d_b, d_c);
483
484 // Create a table with the ArrayStruct.
485 ArrayTable.startArrayTable(builder);
486 ArrayTable.addA(builder, arrayOffset);
487 int tableOffset = ArrayTable.endArrayTable(builder);
488
489 ArrayTable.finishArrayTableBuffer(builder, tableOffset);
490
491 ArrayTable table = ArrayTable.getRootAsArrayTable(builder.dataBuffer());
492 NestedStruct nested = new NestedStruct();
493
494 TestEq(table.a().a(), 0.5f);
495 for (int i = 0; i < 15; i++) TestEq(table.a().b(i), i);
496 TestEq(table.a().c(), (byte)1);
497 TestEq(table.a().d(nested, 0).a(0), 1);
498 TestEq(table.a().d(nested, 0).a(1), 2);
499 TestEq(table.a().d(nested, 1).a(0), 3);
500 TestEq(table.a().d(nested, 1).a(1), 4);
501 TestEq(table.a().d(nested, 0).b(), TestEnum.B);
502 TestEq(table.a().d(nested, 1).b(), TestEnum.C);
503 TestEq(table.a().d(nested, 0).c(0), TestEnum.A);
504 TestEq(table.a().d(nested, 0).c(1), TestEnum.B);
505 TestEq(table.a().d(nested, 1).c(0), TestEnum.C);
506 TestEq(table.a().d(nested, 1).c(1), TestEnum.B);
507 }
508
509 static <T> void TestEq(T a, T b) {
510 if (!a.equals(b)) {
511 System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
512 System.out.println("FlatBuffers test FAILED: \'" + a + "\' != \'" + b + "\'");
513 assert false;
514 System.exit(1);
515 }
516 }
517}