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