blob: 07f0465a40823fed94630f63e5d53c4014a52e9d [file] [log] [blame]
/*
* 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 MyGame.Example.*
import com.google.flatbuffers.ByteBufferUtil
import com.google.flatbuffers.FlatBufferBuilder
import NamespaceA.*
import NamespaceA.NamespaceB.*
import NamespaceA.NamespaceB.TableInNestedNS
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.channels.FileChannel
import com.google.flatbuffers.Constants.SIZE_PREFIX_LENGTH
@kotlin.ExperimentalUnsignedTypes
class KotlinTest {
companion object {
@JvmStatic
fun main(args: Array<String>) {
// First, let's test reading a FlatBuffer generated by C++ code:
// This file was generated from monsterdata_test.json
val data = RandomAccessFile(File("monsterdata_test.mon"), "r").use {
val temp = ByteArray(it.length().toInt())
it.readFully(temp)
temp
}
// Now test it:
val 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.
val fbb = FlatBufferBuilder(1)
TestBuilderBasics(fbb, true)
TestBuilderBasics(fbb, false)
TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer())
TestNamespaceNesting()
TestNestedFlatBuffer()
TestCreateByteVector()
TestCreateUninitializedVector()
TestByteBufferFactory()
TestSizedInputStream()
TestVectorOfUnions()
println("FlatBuffers test: completed successfully")
}
fun TestEnums() {
assert(Color.name(Color.Red.toInt()) == "Red")
assert(Color.name(Color.Blue.toInt()) == "Blue")
assert(Any_.name(Any_.NONE.toInt()) == "NONE")
assert(Any_.name(Any_.Monster.toInt()) == "Monster")
}
fun TestBuffer(bb: ByteBuffer) {
assert(Monster.MonsterBufferHasIdentifier(bb) == true)
val monster = Monster.getRootAsMonster(bb)
assert(monster.hp == 80.toShort())
assert(monster.mana == 150.toShort()) // default
assert(monster.name == "MyMonster")
// monster.friendly() // can't access, deprecated
val pos = monster.pos!!
assert(pos.x == 1.0f)
assert(pos.y == 2.0f)
assert(pos.z == 3.0f)
assert(pos.test1 == 3.0)
// issue: int != byte
assert(pos.test2 == Color.Green)
val t = pos.test3!!
assert(t.a == 5.toShort())
assert(t.b == 6.toByte())
assert(monster.testType == Any_.Monster)
val monster2 = Monster()
assert(monster.test(monster2) != null == true)
assert(monster2.name == "Fred")
assert(monster.inventoryLength == 5)
var invsum = 0u
for (i in 0 until monster.inventoryLength)
invsum += monster.inventory(i)
assert(invsum == 10u)
// Alternative way of accessing a vector:
val ibb = monster.inventoryAsByteBuffer
invsum = 0u
while (ibb.position() < ibb.limit())
invsum += ibb.get().toUInt()
assert(invsum == 10u)
val test_0 = monster.test4(0)!!
val test_1 = monster.test4(1)!!
assert(monster.test4Length == 2)
assert(test_0.a + test_0.b + test_1.a + test_1.b == 100)
assert(monster.testarrayofstringLength == 2)
assert(monster.testarrayofstring(0) == "test1")
assert(monster.testarrayofstring(1) == "test2")
assert(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
fun TestExtendedBuffer(bb: ByteBuffer) {
TestBuffer(bb)
val monster = Monster.getRootAsMonster(bb)
assert(monster.testhashu32Fnv1 == (1u + Integer.MAX_VALUE.toUInt()))
}
fun TestNamespaceNesting() {
// reference / manipulate these to verify compilation
val fbb = FlatBufferBuilder(1)
TableInNestedNS.startTableInNestedNS(fbb)
TableInNestedNS.addFoo(fbb, 1234)
val nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb)
TableInFirstNS.startTableInFirstNS(fbb)
TableInFirstNS.addFooTable(fbb, nestedTableOff)
}
fun TestNestedFlatBuffer() {
val nestedMonsterName = "NestedMonsterName"
val nestedMonsterHp: Short = 600
val nestedMonsterMana: Short = 1024
var fbb1: FlatBufferBuilder? = FlatBufferBuilder(16)
val str1 = fbb1!!.createString(nestedMonsterName)
Monster.startMonster(fbb1)
Monster.addName(fbb1, str1)
Monster.addHp(fbb1, nestedMonsterHp)
Monster.addMana(fbb1, nestedMonsterMana)
val monster1 = Monster.endMonster(fbb1)
Monster.finishMonsterBuffer(fbb1, monster1)
val fbb1Bytes = fbb1.sizedByteArray()
val fbb2 = FlatBufferBuilder(16)
val str2 = fbb2.createString("My Monster")
val nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes.asUByteArray())
Monster.startMonster(fbb2)
Monster.addName(fbb2, str2)
Monster.addHp(fbb2, 50.toShort())
Monster.addMana(fbb2, 32.toShort())
Monster.addTestnestedflatbuffer(fbb2, nestedBuffer)
val monster = Monster.endMonster(fbb2)
Monster.finishMonsterBuffer(fbb2, monster)
// Now test the data extracted from the nested buffer
val mons = Monster.getRootAsMonster(fbb2.dataBuffer())
val nestedMonster = mons.testnestedflatbufferAsMonster!!
assert(nestedMonsterMana == nestedMonster.mana)
assert(nestedMonsterHp == nestedMonster.hp)
assert(nestedMonsterName == nestedMonster.name)
}
fun TestCreateByteVector() {
val fbb = FlatBufferBuilder(16)
val str = fbb.createString("MyMonster")
val inventory = byteArrayOf(0, 1, 2, 3, 4)
val vec = fbb.createByteVector(inventory)
Monster.startMonster(fbb)
Monster.addInventory(fbb, vec)
Monster.addName(fbb, str)
val monster1 = Monster.endMonster(fbb)
Monster.finishMonsterBuffer(fbb, monster1)
val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer())
assert(monsterObject.inventory(1) == inventory[1].toUByte())
assert(monsterObject.inventoryLength == inventory.size)
assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer)
}
fun TestCreateUninitializedVector() {
val fbb = FlatBufferBuilder(16)
val str = fbb.createString("MyMonster")
val inventory = byteArrayOf(0, 1, 2, 3, 4)
val bb = fbb.createUnintializedVector(1, inventory.size, 1)
for (i in inventory) {
bb.put(i)
}
val vec = fbb.endVector()
Monster.startMonster(fbb)
Monster.addInventory(fbb, vec)
Monster.addName(fbb, str)
val monster1 = Monster.endMonster(fbb)
Monster.finishMonsterBuffer(fbb, monster1)
val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer())
assert(monsterObject.inventory(1) == inventory[1].toUByte())
assert(monsterObject.inventoryLength == inventory.size)
assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer)
}
fun TestByteBufferFactory() {
class MappedByteBufferFactory : FlatBufferBuilder.ByteBufferFactory() {
override fun newByteBuffer(capacity: Int): ByteBuffer? {
var bb: ByteBuffer?
try {
bb = RandomAccessFile("javatest.bin", "rw").channel.map(
FileChannel.MapMode.READ_WRITE,
0,
capacity.toLong()
).order(ByteOrder.LITTLE_ENDIAN)
} catch (e: Throwable) {
println("FlatBuffers test: couldn't map ByteBuffer to a file")
bb = null
}
return bb
}
}
val fbb = FlatBufferBuilder(1, MappedByteBufferFactory())
TestBuilderBasics(fbb, false)
}
fun TestSizedInputStream() {
// Test on default FlatBufferBuilder that uses HeapByteBuffer
val fbb = FlatBufferBuilder(1)
TestBuilderBasics(fbb, false)
val `in` = fbb.sizedInputStream()
val array = fbb.sizedByteArray()
var count = 0
var currentVal = 0
while (currentVal != -1 && count < array.size) {
try {
currentVal = `in`.read()
} catch (e: java.io.IOException) {
println("FlatBuffers test: couldn't read from InputStream")
return
}
assert(currentVal.toByte() == array[count])
count++
}
assert(count == array.size)
}
fun TestBuilderBasics(fbb: FlatBufferBuilder, sizePrefix: Boolean) {
val names = intArrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
val off = IntArray(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)
val sortMons = fbb.createSortedVectorOfTables(Monster(), off)
// We set up the same values as monsterdata.json:
val str = fbb.createString("MyMonster")
val inv = Monster.createInventoryVector(fbb, byteArrayOf(0, 1, 2, 3, 4).asUByteArray())
val fred = fbb.createString("Fred")
Monster.startMonster(fbb)
Monster.addName(fbb, fred)
val mon2 = Monster.endMonster(fbb)
Monster.startTest4Vector(fbb, 2)
Test.createTest(fbb, 10.toShort(), 20.toByte())
Test.createTest(fbb, 30.toShort(), 40.toByte())
val test4 = fbb.endVector()
val testArrayOfString =
Monster.createTestarrayofstringVector(fbb, intArrayOf(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, 5.toShort(), 6.toByte()
)
)
Monster.addHp(fbb, 80.toShort())
Monster.addName(fbb, str)
Monster.addInventory(fbb, inv)
Monster.addTestType(fbb, Any_.Monster)
Monster.addTest(fbb, mon2)
Monster.addTest4(fbb, test4)
Monster.addTestarrayofstring(fbb, testArrayOfString)
Monster.addTestbool(fbb, true)
Monster.addTesthashu32Fnv1(fbb, UInt.MAX_VALUE + 1u)
Monster.addTestarrayoftables(fbb, sortMons)
val 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 {
val filename = "monsterdata_java_wire" + (if (sizePrefix) "_sp" else "") + ".mon"
val fc = FileOutputStream(filename).channel
fc.write(fbb.dataBuffer().duplicate())
fc.close()
} catch (e: java.io.IOException) {
println("FlatBuffers test: couldn't write file")
return
}
// Test it:
var dataBuffer = fbb.dataBuffer()
if (sizePrefix) {
assert(
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
val 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
assert(monster.mutateMana(10.toShort()) == false)
assert(monster.mana == 150.toShort())
// Accessing a vector of sorted by the key tables
assert(monster.testarrayoftables(0)!!.name == "Barney")
assert(monster.testarrayoftables(1)!!.name == "Frodo")
assert(monster.testarrayoftables(2)!!.name == "Wilma")
// Example of searching for a table by the key
assert(monster.testarrayoftablesByKey("Frodo")!!.name == "Frodo")
assert(monster.testarrayoftablesByKey("Barney")!!.name == "Barney")
assert(monster.testarrayoftablesByKey("Wilma")!!.name == "Wilma")
// testType is an existing field and mutating it should succeed
assert(monster.testType == Any_.Monster)
assert(monster.mutateTestType(Any_.NONE) == true)
assert(monster.testType == Any_.NONE)
assert(monster.mutateTestType(Any_.Monster) == true)
assert(monster.testType == Any_.Monster)
//mutate the inventory vector
assert(monster.mutateInventory(0, 1u) == true)
assert(monster.mutateInventory(1, 2u) == true)
assert(monster.mutateInventory(2, 3u) == true)
assert(monster.mutateInventory(3, 4u) == true)
assert(monster.mutateInventory(4, 5u) == true)
for (i in 0 until monster.inventoryLength) {
assert(monster.inventory(i) == (i.toUByte() + 1u).toUByte())
}
//reverse mutation
assert(monster.mutateInventory(0, 0u) == true)
assert(monster.mutateInventory(1, 1u) == true)
assert(monster.mutateInventory(2, 2u) == true)
assert(monster.mutateInventory(3, 3u) == true)
assert(monster.mutateInventory(4, 4u) == true)
// get a struct field and edit one of its fields
val pos = monster.pos!!
assert(pos.x == 1.0f)
pos.mutateX(55.0f)
assert(pos.x == 55.0f)
pos.mutateX(1.0f)
assert(pos.x == 1.0f)
}
fun TestVectorOfUnions() {
val fbb = FlatBufferBuilder()
val swordAttackDamage = 1
val characterVector = intArrayOf(Attacker.createAttacker(fbb, swordAttackDamage))
val characterTypeVector = ubyteArrayOf(Character_.MuLan)
Movie.finishMovieBuffer(
fbb,
Movie.createMovie(
fbb,
0u,
0,
Movie.createCharactersTypeVector(fbb, characterTypeVector),
Movie.createCharactersVector(fbb, characterVector)
)
)
val movie = Movie.getRootAsMovie(fbb.dataBuffer())
assert(movie.charactersTypeLength == characterTypeVector.size)
assert(movie.charactersLength == characterVector.size)
assert(movie.charactersType(0) == characterTypeVector[0])
assert((movie.characters(Attacker(), 0) as Attacker).swordAttackDamage == swordAttackDamage)
}
}
}