content: /*
   * Copyright 2014 Google Inc. All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.io.*;
  import java.nio.ByteBuffer;
  import java.nio.ByteOrder;
  import java.nio.channels.FileChannel;
  import MyGame.Example.*;
  import NamespaceA.*;
  import NamespaceA.NamespaceB.*;
  import com.google.flatbuffers.ByteBufferUtil;
  import static com.google.flatbuffers.Constants.*;
  import com.google.flatbuffers.FlatBufferBuilder;
  
  class JavaTest {
      public static void main(String[] args) {
  
          // First, let's test reading a FlatBuffer generated by C++ code:
          // This file was generated from monsterdata_test.json
  
          byte[] data = null;
          File file = new File("monsterdata_test.mon");
          RandomAccessFile f = null;
          try {
              f = new RandomAccessFile(file, "r");
              data = new byte[(int)f.length()];
              f.readFully(data);
              f.close();
          } catch(java.io.IOException e) {
              System.out.println("FlatBuffers test: couldn't read file");
              return;
          }
  
          // Now test it:
  
          ByteBuffer bb = ByteBuffer.wrap(data);
          TestBuffer(bb);
  
          // Second, let's create a FlatBuffer from scratch in Java, and test it also.
          // We use an initial size of 1 to exercise the reallocation algorithm,
          // normally a size larger than the typical FlatBuffer you generate would be
          // better for performance.
          FlatBufferBuilder fbb = new FlatBufferBuilder(1);
  
          TestBuilderBasics(fbb, true);
          TestBuilderBasics(fbb, false);
  
          TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
  
          TestNamespaceNesting();
  
          TestNestedFlatBuffer();
  
          TestCreateByteVector();
  
          TestCreateUninitializedVector();
  
          TestByteBufferFactory();
  
          TestSizedInputStream();
  
          System.out.println("FlatBuffers test: completed successfully");
      }
  
      static void TestEnums() {
        TestEq(Color.name(Color.Red), "Red");
        TestEq(Color.name(Color.Blue), "Blue");
        TestEq(Any.name(Any.NONE), "NONE");
        TestEq(Any.name(Any.Monster), "Monster");
      }
  
      static void TestBuffer(ByteBuffer bb) {
          TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
  
          Monster monster = Monster.getRootAsMonster(bb);
  
          TestEq(monster.hp(), (short)80);
          TestEq(monster.mana(), (short)150);  // default
  
          TestEq(monster.name(), "MyMonster");
          // monster.friendly() // can't access, deprecated
  
          Vec3 pos = monster.pos();
          TestEq(pos.x(), 1.0f);
          TestEq(pos.y(), 2.0f);
          TestEq(pos.z(), 3.0f);
          TestEq(pos.test1(), 3.0);
          TestEq(pos.test2(), Color.Green);
          Test t = pos.test3();
          TestEq(t.a(), (short)5);
          TestEq(t.b(), (byte)6);
  
          TestEq(monster.testType(), (byte)Any.Monster);
          Monster monster2 = new Monster();
          TestEq(monster.test(monster2) != null, true);
          TestEq(monster2.name(), "Fred");
  
          TestEq(monster.inventoryLength(), 5);
          int invsum = 0;
          for (int i = 0; i < monster.inventoryLength(); i++)
              invsum += monster.inventory(i);
          TestEq(invsum, 10);
  
          // Alternative way of accessing a vector:
          ByteBuffer ibb = monster.inventoryAsByteBuffer();
          invsum = 0;
          while (ibb.position() < ibb.limit())
              invsum += ibb.get();
          TestEq(invsum, 10);
  
          Test test_0 = monster.test4(0);
          Test test_1 = monster.test4(1);
          TestEq(monster.test4Length(), 2);
          TestEq(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
  
          TestEq(monster.testarrayofstringLength(), 2);
          TestEq(monster.testarrayofstring(0),"test1");
          TestEq(monster.testarrayofstring(1),"test2");
  
          TestEq(monster.testbool(), true);
      }
  
      // this method checks additional fields not present in the binary buffer read from file
      // these new tests are performed on top of the regular tests
      static void TestExtendedBuffer(ByteBuffer bb) {
          TestBuffer(bb);
  
          Monster monster = Monster.getRootAsMonster(bb);
  
          TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
      }
  
      static void TestNamespaceNesting() {
          // reference / manipulate these to verify compilation
          FlatBufferBuilder fbb = new FlatBufferBuilder(1);
  
          TableInNestedNS.startTableInNestedNS(fbb);
          TableInNestedNS.addFoo(fbb, 1234);
          int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
  
          TableInFirstNS.startTableInFirstNS(fbb);
          TableInFirstNS.addFooTable(fbb, nestedTableOff);
          int off = TableInFirstNS.endTableInFirstNS(fbb);
      }
  
      static void TestNestedFlatBuffer() {
          final String nestedMonsterName = "NestedMonsterName";
          final short nestedMonsterHp = 600;
          final short nestedMonsterMana = 1024;
  
          FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
          int str1 = fbb1.createString(nestedMonsterName);
          Monster.startMonster(fbb1);
          Monster.addName(fbb1, str1);
          Monster.addHp(fbb1, nestedMonsterHp);
          Monster.addMana(fbb1, nestedMonsterMana);
          int monster1 = Monster.endMonster(fbb1);
          Monster.finishMonsterBuffer(fbb1, monster1);
          byte[] fbb1Bytes = fbb1.sizedByteArray();
          fbb1 = null;
  
          FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
          int str2 = fbb2.createString("My Monster");
          int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
          Monster.startMonster(fbb2);
          Monster.addName(fbb2, str2);
          Monster.addHp(fbb2, (short)50);
          Monster.addMana(fbb2, (short)32);
          Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
          int monster = Monster.endMonster(fbb2);
          Monster.finishMonsterBuffer(fbb2, monster);
  
          // Now test the data extracted from the nested buffer
          Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
          Monster nestedMonster = mons.testnestedflatbufferAsMonster();
  
          TestEq(nestedMonsterMana, nestedMonster.mana());
          TestEq(nestedMonsterHp, nestedMonster.hp());
          TestEq(nestedMonsterName, nestedMonster.name());
      }
  
      static void TestCreateByteVector() {
          FlatBufferBuilder fbb = new FlatBufferBuilder(16);
          int str = fbb.createString("MyMonster");
          byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
          int vec = fbb.createByteVector(inventory);
          Monster.startMonster(fbb);
          Monster.addInventory(fbb, vec);
          Monster.addName(fbb, str);
          int monster1 = Monster.endMonster(fbb);
          Monster.finishMonsterBuffer(fbb, monster1);
          Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
  
          TestEq(monsterObject.inventory(1), (int)inventory[1]);
          TestEq(monsterObject.inventoryLength(), inventory.length);
          TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
      }
  
      static void TestCreateUninitializedVector() {
          FlatBufferBuilder fbb = new FlatBufferBuilder(16);
          int str = fbb.createString("MyMonster");
          byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
          ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1);
          for (byte i:inventory) {
              bb.put(i);
          }
          int vec = fbb.endVector();
          Monster.startMonster(fbb);
          Monster.addInventory(fbb, vec);
          Monster.addName(fbb, str);
          int monster1 = Monster.endMonster(fbb);
          Monster.finishMonsterBuffer(fbb, monster1);
          Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
  
          TestEq(monsterObject.inventory(1), (int)inventory[1]);
          TestEq(monsterObject.inventoryLength(), inventory.length);
          TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
      }
  
      static void TestByteBufferFactory() {
          final class MappedByteBufferFactory implements FlatBufferBuilder.ByteBufferFactory {
              @Override
              public ByteBuffer newByteBuffer(int capacity) {
                  ByteBuffer bb;
                  try {
                      bb =  new RandomAccessFile("javatest.bin", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, capacity).order(ByteOrder.LITTLE_ENDIAN);
                  } catch(Throwable e) {
                      System.out.println("FlatBuffers test: couldn't map ByteBuffer to a file");
                      bb = null;
                  }
                  return bb;
              }
          }
  
          FlatBufferBuilder fbb = new FlatBufferBuilder(1, new MappedByteBufferFactory());
  
          TestBuilderBasics(fbb, false);
      }
  
      static void TestSizedInputStream() {
          // Test on default FlatBufferBuilder that uses HeapByteBuffer
          FlatBufferBuilder fbb = new FlatBufferBuilder(1);
  
          TestBuilderBasics(fbb, false);
  
          InputStream in = fbb.sizedInputStream();
          byte[] array = fbb.sizedByteArray();
          int count = 0;
          int currentVal = 0;
  
          while (currentVal != -1 && count < array.length) {
              try {
                  currentVal = in.read();
              } catch(java.io.IOException e) {
                  System.out.println("FlatBuffers test: couldn't read from InputStream");
                  return;
              }
              TestEq((byte)currentVal, array[count]);
              count++;
          }
          TestEq(count, array.length);
      }
  
      static void TestBuilderBasics(FlatBufferBuilder fbb, boolean sizePrefix) {
          int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
          int[] off = new int[3];
          Monster.startMonster(fbb);
          Monster.addName(fbb, names[0]);
          off[0] = Monster.endMonster(fbb);
          Monster.startMonster(fbb);
          Monster.addName(fbb, names[1]);
          off[1] = Monster.endMonster(fbb);
          Monster.startMonster(fbb);
          Monster.addName(fbb, names[2]);
          off[2] = Monster.endMonster(fbb);
          int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
  
          // We set up the same values as monsterdata.json:
  
          int str = fbb.createString("MyMonster");
  
          int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
  
          int fred = fbb.createString("Fred");
          Monster.startMonster(fbb);
          Monster.addName(fbb, fred);
          int mon2 = Monster.endMonster(fbb);
  
          Monster.startTest4Vector(fbb, 2);
          Test.createTest(fbb, (short)10, (byte)20);
          Test.createTest(fbb, (short)30, (byte)40);
          int test4 = fbb.endVector();
  
          int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
                  fbb.createString("test1"),
                  fbb.createString("test2")
          });
  
          Monster.startMonster(fbb);
          Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
                  Color.Green, (short)5, (byte)6));
          Monster.addHp(fbb, (short)80);
          Monster.addName(fbb, str);
          Monster.addInventory(fbb, inv);
          Monster.addTestType(fbb, (byte)Any.Monster);
          Monster.addTest(fbb, mon2);
          Monster.addTest4(fbb, test4);
          Monster.addTestarrayofstring(fbb, testArrayOfString);
          Monster.addTestbool(fbb, true);
          Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
          Monster.addTestarrayoftables(fbb, sortMons);
          int mon = Monster.endMonster(fbb);
  
          if (sizePrefix) {
              Monster.finishSizePrefixedMonsterBuffer(fbb, mon);
          } else {
              Monster.finishMonsterBuffer(fbb, mon);
          }
  
          // Write the result to a file for debugging purposes:
          // Note that the binaries are not necessarily identical, since the JSON
          // parser may serialize in a slightly different order than the above
          // Java code. They are functionally equivalent though.
  
          try {
              String filename = "monsterdata_java_wire" + (sizePrefix ? "_sp" : "") + ".mon";
              FileChannel fc = new FileOutputStream(filename).getChannel();
              fc.write(fbb.dataBuffer().duplicate());
              fc.close();
          } catch(java.io.IOException e) {
              System.out.println("FlatBuffers test: couldn't write file");
              return;
          }
  
          // Test it:
          ByteBuffer dataBuffer = fbb.dataBuffer();
          if (sizePrefix) {
              TestEq(ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH,
                     dataBuffer.remaining());
              dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer);
          }
          TestExtendedBuffer(dataBuffer);
  
          // Make sure it also works with read only ByteBuffers. This is slower,
          // since creating strings incurs an additional copy
          // (see Table.__string).
          TestExtendedBuffer(dataBuffer.asReadOnlyBuffer());
  
          TestEnums();
  
          //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
          // revert to original values after testing
          Monster monster = Monster.getRootAsMonster(dataBuffer);
  
          // mana is optional and does not exist in the buffer so the mutation should fail
          // the mana field should retain its default value
          TestEq(monster.mutateMana((short)10), false);
          TestEq(monster.mana(), (short)150);
  
          // Accessing a vector of sorted by the key tables
          TestEq(monster.testarrayoftables(0).name(), "Barney");
          TestEq(monster.testarrayoftables(1).name(), "Frodo");
          TestEq(monster.testarrayoftables(2).name(), "Wilma");
  
          // Example of searching for a table by the key
          TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
          TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
          TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
  
          // testType is an existing field and mutating it should succeed
          TestEq(monster.testType(), (byte)Any.Monster);
          TestEq(monster.mutateTestType(Any.NONE), true);
          TestEq(monster.testType(), (byte)Any.NONE);
          TestEq(monster.mutateTestType(Any.Monster), true);
          TestEq(monster.testType(), (byte)Any.Monster);
  
          //mutate the inventory vector
          TestEq(monster.mutateInventory(0, 1), true);
          TestEq(monster.mutateInventory(1, 2), true);
          TestEq(monster.mutateInventory(2, 3), true);
          TestEq(monster.mutateInventory(3, 4), true);
          TestEq(monster.mutateInventory(4, 5), true);
  
          for (int i = 0; i < monster.inventoryLength(); i++) {
              TestEq(monster.inventory(i), i + 1);
          }
  
          //reverse mutation
          TestEq(monster.mutateInventory(0, 0), true);
          TestEq(monster.mutateInventory(1, 1), true);
          TestEq(monster.mutateInventory(2, 2), true);
          TestEq(monster.mutateInventory(3, 3), true);
          TestEq(monster.mutateInventory(4, 4), true);
  
          // get a struct field and edit one of its fields
          Vec3 pos = monster.pos();
          TestEq(pos.x(), 1.0f);
          pos.mutateX(55.0f);
          TestEq(pos.x(), 55.0f);
          pos.mutateX(1.0f);
          TestEq(pos.x(), 1.0f);
      }
  
      static <T> void TestEq(T a, T b) {
          if (!a.equals(b)) {
              System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
              System.out.println("FlatBuffers test FAILED: \'" + a + "\' != \'" + b + "\'");
              assert false;
              System.exit(1);
          }
      }
  }
  