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