blob: 07f0465a40823fed94630f63e5d53c4014a52e9d [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
17import MyGame.Example.*
18import com.google.flatbuffers.ByteBufferUtil
19import com.google.flatbuffers.FlatBufferBuilder
20import NamespaceA.*
21import NamespaceA.NamespaceB.*
22import NamespaceA.NamespaceB.TableInNestedNS
23import java.io.File
24import java.io.FileOutputStream
25import java.io.InputStream
26import java.io.RandomAccessFile
27import java.nio.ByteBuffer
28import java.nio.ByteOrder
29import java.nio.channels.FileChannel
30
31import com.google.flatbuffers.Constants.SIZE_PREFIX_LENGTH
32
33@kotlin.ExperimentalUnsignedTypes
34class KotlinTest {
35
36 companion object {
37 @JvmStatic
38 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
82 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
89 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
144 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
152 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
164 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
199 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
216 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
237 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
261 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
286 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
430 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 }