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