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