/* * Copyright 2021 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 XCTest @testable import FlatBuffers final class FlatBuffersUnionTests: XCTestCase { func testCreateMonstor() { var b = FlatBufferBuilder(initialSize: 20) let dmg: Int16 = 5 let str = "Axe" let axe = b.create(string: str) let weapon = Weapon.createWeapon(builder: &b, offset: axe, dmg: dmg) let weapons = b.createVector(ofOffsets: [weapon]) let root = LocalMonster.createMonster( builder: &b, offset: weapons, equipment: .Weapon, equippedOffset: weapon.o) b.finish(offset: root) let buffer = b.sizedByteArray XCTAssertEqual(buffer, [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 8, 0, 7, 0, 12, 0, 10, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 20, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0]) let monster = LocalMonster.getRootAsMonster(bb: ByteBuffer(bytes: buffer)) XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg) XCTAssertEqual(monster.weapon(at: 0)?.name, str) XCTAssertEqual(monster.weapon(at: 0)?.nameVector, [65, 120, 101]) let p: Weapon? = monster.equiped() XCTAssertEqual(p?.dmg, dmg) XCTAssertEqual(p?.name, str) XCTAssertEqual(p?.nameVector, [65, 120, 101]) } func testEndTableFinish() { var builder = FlatBufferBuilder(initialSize: 20) let sword = builder.create(string: "Sword") let axe = builder.create(string: "Axe") let weaponOne = Weapon.createWeapon(builder: &builder, offset: sword, dmg: 3) let weaponTwo = Weapon.createWeapon(builder: &builder, offset: axe, dmg: 5) let name = builder.create(string: "Orc") let inventory: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] let inv = builder.createVector(inventory, size: 10) let weapons = builder.createVector(ofOffsets: [weaponOne, weaponTwo]) let path = builder.createVector(ofStructs: [ Vec(x: 4.0, y: 5.0, z: 6.0), Vec(x: 1.0, y: 2.0, z: 3.0), ]) let orc = FinalMonster.createMonster( builder: &builder, position: Vec(x: 1, y: 2, z: 3), hp: 300, name: name, inventory: inv, color: .red, weapons: weapons, equipment: .Weapon, equippedOffset: weaponTwo, path: path) builder.finish(offset: orc) XCTAssertEqual(builder.sizedByteArray, [32, 0, 0, 0, 0, 0, 26, 0, 48, 0, 36, 0, 0, 0, 34, 0, 28, 0, 0, 0, 24, 0, 23, 0, 16, 0, 15, 0, 8, 0, 4, 0, 26, 0, 0, 0, 44, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 76, 0, 0, 0, 0, 0, 44, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 10, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 3, 0, 0, 0, 79, 114, 99, 0, 244, 255, 255, 255, 0, 0, 5, 0, 24, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 3, 0, 12, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0, 5, 0, 0, 0, 83, 119, 111, 114, 100, 0, 0, 0]) } func testEnumVector() { let vectorOfEnums: [ColorsNameSpace.RGB] = [.blue, .green] var builder = FlatBufferBuilder(initialSize: 1) let off = builder.createVector(vectorOfEnums) let start = ColorsNameSpace.Monster.startMonster(&builder) ColorsNameSpace.Monster.add(colors: off, &builder) let end = ColorsNameSpace.Monster.endMonster(&builder, start: start) builder.finish(offset: end) XCTAssertEqual(builder.sizedByteArray, [12, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0]) let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer) XCTAssertEqual(monster.colorsCount, 2) XCTAssertEqual(monster.colors(at: 0), .blue) XCTAssertEqual(monster.colors(at: 1), .green) } func testUnionVector() { var fb = FlatBufferBuilder() let swordDmg: Int32 = 8 let attackStart = Attacker.startAttacker(&fb) Attacker.add(swordAttackDamage: swordDmg, &fb) let attack = Attacker.endAttacker(&fb, start: attackStart) let characterType: [Character] = [.belle, .mulan, .bookfan] let characters = [ fb.create(struct: BookReader(booksRead: 7)), attack, fb.create(struct: BookReader(booksRead: 2)), ] let types = fb.createVector(characterType) let characterVector = fb.createVector(ofOffsets: characters) let end = Movie.createMovie( &fb, charactersTypeVectorOffset: types, charactersVectorOffset: characterVector) Movie.finish(&fb, end: end) var movie = Movie.getRootAsMovie(bb: fb.buffer) XCTAssertEqual(movie.charactersTypeCount, Int32(characterType.count)) XCTAssertEqual(movie.charactersCount, Int32(characters.count)) for i in 0...size } var value: Int32 { rawValue } case red = 0, green = 1, blue = 2 } struct Monster: FlatBufferObject { var __buffer: ByteBuffer! { _accessor.bb } private var _accessor: Table static func getRootAsMonster(bb: ByteBuffer) -> Monster { Monster(Table( bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } init(_ t: Table) { _accessor = t } init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } public var colorsCount: Int32 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.vector(count: o) } public func colors(at index: Int32) -> ColorsNameSpace.RGB? { let o = _accessor.offset(4); return o == 0 ? ColorsNameSpace.RGB(rawValue: 0)! : ColorsNameSpace.RGB(rawValue: _accessor.directRead( of: Int32.self, offset: _accessor.vector(at: o) + index * 4)) } static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } static func add(colors: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add( offset: colors, at: 4) } static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } } } enum Equipment: Byte { case none, Weapon } enum Color3: Int8 { case red = 0, green, blue } struct FinalMonster { @inlinable static func createMonster( builder: inout FlatBufferBuilder, position: Vec, hp: Int16, name: Offset, inventory: Offset, color: Color3, weapons: Offset, equipment: Equipment = .none, equippedOffset: Offset, path: Offset) -> Offset { let start = builder.startTable(with: 11) builder.create(struct: position, position: 4) builder.add(element: hp, def: 100, at: 8) builder.add(offset: name, at: 10) builder.add(offset: inventory, at: 14) builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 16) builder.add(offset: weapons, at: 18) builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 20) builder.add(offset: equippedOffset, at: 22) builder.add(offset: path, at: 24) return Offset(offset: builder.endTable(at: start)) } } struct LocalMonster { private var __t: Table init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o) } init(_ t: Table) { __t = t } func weapon(at index: Int32) -> Weapon? { let o = __t.offset(4); return o == 0 ? nil : Weapon.assign( __t.indirect(__t.vector(at: o) + (index * 4)), __t.bb) } func equiped() -> T? { let o = __t.offset(8); return o == 0 ? nil : __t.union(o) } static func getRootAsMonster(bb: ByteBuffer) -> LocalMonster { LocalMonster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0)))) } @inlinable static func createMonster( builder: inout FlatBufferBuilder, offset: Offset, equipment: Equipment = .none, equippedOffset: UOffset) -> Offset { let start = builder.startTable(with: 3) builder.add(element: equippedOffset, def: 0, at: 8) builder.add(offset: offset, at: 4) builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 6) return Offset(offset: builder.endTable(at: start)) } } struct Weapon: FlatBufferObject { var __buffer: ByteBuffer! { __t.bb } static let offsets: (name: VOffset, dmg: VOffset) = (4, 6) private var __t: Table init(_ t: Table) { __t = t } init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)} var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int16.self, at: o) } var nameVector: [UInt8]? { __t.getVector(at: 4) } var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) } static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(bb: bb, position: i)) } @inlinable static func createWeapon( builder: inout FlatBufferBuilder, offset: Offset, dmg: Int16) -> Offset { let _start = builder.startTable(with: 2) Weapon.add(builder: &builder, name: offset) Weapon.add(builder: &builder, dmg: dmg) return Weapon.end(builder: &builder, startOffset: _start) } @inlinable static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset { Offset(offset: builder.endTable(at: startOffset)) } @inlinable static func add(builder: inout FlatBufferBuilder, name: Offset) { builder.add(offset: name, at: Weapon.offsets.name) } @inlinable static func add(builder: inout FlatBufferBuilder, dmg: Int16) { builder.add(element: dmg, def: 0, at: Weapon.offsets.dmg) } }