1 /* 2 * Copyright 2021 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 XCTest 18 @testable import FlatBuffers 19 20 final class FlatBuffersUnionTests: XCTestCase { 21 testCreateMonstornull22 func testCreateMonstor() { 23 24 var b = FlatBufferBuilder(initialSize: 20) 25 let dmg: Int16 = 5 26 let str = "Axe" 27 let axe = b.create(string: str) 28 let weapon = Weapon.createWeapon(builder: &b, offset: axe, dmg: dmg) 29 let weapons = b.createVector(ofOffsets: [weapon]) 30 let root = LocalMonster.createMonster( 31 builder: &b, 32 offset: weapons, 33 equipment: .Weapon, 34 equippedOffset: weapon.o) 35 b.finish(offset: root) 36 let buffer = b.sizedByteArray 37 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]) 38 let monster = LocalMonster.getRootAsMonster(bb: ByteBuffer(bytes: buffer)) 39 XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg) 40 XCTAssertEqual(monster.weapon(at: 0)?.name, str) 41 XCTAssertEqual(monster.weapon(at: 0)?.nameVector, [65, 120, 101]) 42 let p: Weapon? = monster.equiped() 43 XCTAssertEqual(p?.dmg, dmg) 44 XCTAssertEqual(p?.name, str) 45 XCTAssertEqual(p?.nameVector, [65, 120, 101]) 46 } 47 testEndTableFinishnull48 func testEndTableFinish() { 49 var builder = FlatBufferBuilder(initialSize: 20) 50 let sword = builder.create(string: "Sword") 51 let axe = builder.create(string: "Axe") 52 let weaponOne = Weapon.createWeapon(builder: &builder, offset: sword, dmg: 3) 53 let weaponTwo = Weapon.createWeapon(builder: &builder, offset: axe, dmg: 5) 54 let name = builder.create(string: "Orc") 55 let inventory: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 56 let inv = builder.createVector(inventory, size: 10) 57 let weapons = builder.createVector(ofOffsets: [weaponOne, weaponTwo]) 58 let path = builder.createVector(ofStructs: [ 59 Vec(x: 4.0, y: 5.0, z: 6.0), 60 Vec(x: 1.0, y: 2.0, z: 3.0), 61 ]) 62 let orc = FinalMonster.createMonster( 63 builder: &builder, 64 position: Vec(x: 1, y: 2, z: 3), 65 hp: 300, 66 name: name, 67 inventory: inv, 68 color: .red, 69 weapons: weapons, 70 equipment: .Weapon, 71 equippedOffset: weaponTwo, 72 path: path) 73 builder.finish(offset: orc) 74 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]) 75 } 76 testEnumVectornull77 func testEnumVector() { 78 let vectorOfEnums: [ColorsNameSpace.RGB] = [.blue, .green] 79 80 var builder = FlatBufferBuilder(initialSize: 1) 81 let off = builder.createVector(vectorOfEnums) 82 let start = ColorsNameSpace.Monster.startMonster(&builder) 83 ColorsNameSpace.Monster.add(colors: off, &builder) 84 let end = ColorsNameSpace.Monster.endMonster(&builder, start: start) 85 builder.finish(offset: end) 86 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]) 87 let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer) 88 XCTAssertEqual(monster.colorsCount, 2) 89 XCTAssertEqual(monster.colors(at: 0), .blue) 90 XCTAssertEqual(monster.colors(at: 1), .green) 91 } 92 testUnionVectornull93 func testUnionVector() { 94 var fb = FlatBufferBuilder() 95 96 let swordDmg: Int32 = 8 97 let attackStart = Attacker.startAttacker(&fb) 98 Attacker.add(swordAttackDamage: swordDmg, &fb) 99 let attack = Attacker.endAttacker(&fb, start: attackStart) 100 101 let characterType: [Character] = [.belle, .mulan, .bookfan] 102 103 let characters = [ 104 fb.create(struct: BookReader(booksRead: 7)), 105 attack, 106 fb.create(struct: BookReader(booksRead: 2)), 107 ] 108 let types = fb.createVector(characterType) 109 let characterVector = fb.createVector(ofOffsets: characters) 110 let end = Movie.createMovie( 111 &fb, 112 charactersTypeVectorOffset: types, 113 charactersVectorOffset: characterVector) 114 Movie.finish(&fb, end: end) 115 116 var movie = Movie.getRootAsMovie(bb: fb.buffer) 117 XCTAssertEqual(movie.charactersTypeCount, Int32(characterType.count)) 118 XCTAssertEqual(movie.charactersCount, Int32(characters.count)) 119 120 for i in 0..<movie.charactersTypeCount { 121 XCTAssertEqual(movie.charactersType(at: i), characterType[Int(i)]) 122 } 123 124 XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) 125 XCTAssertEqual(movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, swordDmg) 126 XCTAssertEqual(movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, 2) 127 128 var objc: MovieT? = movie.unpack() 129 XCTAssertEqual(movie.charactersTypeCount, Int32(objc?.characters.count ?? 0)) 130 XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, (objc?.characters[0]?.value as? BookReader)?.booksRead) 131 fb.clear() 132 let newMovie = Movie.pack(&fb, obj: &objc) 133 fb.finish(offset: newMovie) 134 135 let packedMovie = Movie.getRootAsMovie(bb: fb.buffer) 136 137 XCTAssertEqual(packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead) 138 XCTAssertEqual(packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage) 139 XCTAssertEqual(packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead) 140 } 141 testStringUnionnull142 func testStringUnion() { 143 let string = "Awesome \\\\t\t\nstring!" 144 var fb = FlatBufferBuilder() 145 let stringOffset = fb.create(string: string) 146 let characterType: [Character] = [.bookfan, .other] 147 148 let characters = [ 149 fb.create(struct: BookReader(booksRead: 7)), 150 stringOffset, 151 ] 152 let types = fb.createVector(characterType) 153 let characterVector = fb.createVector(ofOffsets: characters) 154 155 let end = Movie.createMovie( 156 &fb, 157 mainCharacterType: .other, 158 mainCharacterOffset: Offset(offset: stringOffset.o), 159 charactersTypeVectorOffset: types, 160 charactersVectorOffset: characterVector) 161 Movie.finish(&fb, end: end) 162 163 var movie = Movie.getRootAsMovie(bb: fb.sizedBuffer) 164 XCTAssertEqual(movie.mainCharacter(type: String.self), string) 165 XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) 166 XCTAssertEqual(movie.characters(at: 1, type: String.self), string) 167 168 var objc: MovieT? = movie.unpack() 169 XCTAssertEqual(objc?.mainCharacter?.value as? String, string) 170 XCTAssertEqual((objc?.characters[0]?.value as? BookReader)?.booksRead, 7) 171 XCTAssertEqual(objc?.characters[1]?.value as? String, string) 172 fb.clear() 173 let newMovie = Movie.pack(&fb, obj: &objc) 174 fb.finish(offset: newMovie) 175 176 let packedMovie = Movie.getRootAsMovie(bb: fb.buffer) 177 XCTAssertEqual(packedMovie.mainCharacter(type: String.self), string) 178 XCTAssertEqual(packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) 179 XCTAssertEqual(packedMovie.characters(at: 1, type: String.self), string) 180 } 181 } 182 183 public enum ColorsNameSpace { 184 185 enum RGB: Int32, Enum { 186 typealias T = Int32 187 static var byteSize: Int { MemoryLayout<Int32>.size } 188 var value: Int32 { rawValue } 189 case red = 0, green = 1, blue = 2 190 } 191 192 struct Monster: FlatBufferObject { 193 var __buffer: ByteBuffer! { _accessor.bb } 194 195 private var _accessor: Table getRootAsMonsternull196 static func getRootAsMonster(bb: ByteBuffer) -> Monster { Monster(Table( 197 bb: bb, 198 position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } 199 200 init(_ t: Table) { _accessor = t } 201 init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } 202 203 public var colorsCount: Int32 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.vector(count: o) } colorsnull204 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( 205 of: Int32.self, 206 offset: _accessor.vector(at: o) + index * 4)) } startMonsternull207 static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } addnull208 static func add(colors: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add( 209 offset: colors, 210 at: 4) } endMonsternull211 static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } 212 } 213 } 214 215 216 enum Equipment: Byte { case none, Weapon } 217 218 enum Color3: Int8 { case red = 0, green, blue } 219 220 struct FinalMonster { 221 222 @inlinable 223 static func createMonster( 224 builder: inout FlatBufferBuilder, 225 position: Vec, 226 hp: Int16, 227 name: Offset, 228 inventory: Offset, 229 color: Color3, 230 weapons: Offset, 231 equipment: Equipment = .none, 232 equippedOffset: Offset, 233 path: Offset) -> Offset 234 { 235 let start = builder.startTable(with: 11) 236 builder.create(struct: position, position: 4) 237 builder.add(element: hp, def: 100, at: 8) 238 builder.add(offset: name, at: 10) 239 builder.add(offset: inventory, at: 14) 240 builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 16) 241 builder.add(offset: weapons, at: 18) 242 builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 20) 243 builder.add(offset: equippedOffset, at: 22) 244 builder.add(offset: path, at: 24) 245 return Offset(offset: builder.endTable(at: start)) 246 } 247 } 248 249 struct LocalMonster { 250 251 private var __t: Table 252 253 init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o) } 254 init(_ t: Table) { __t = t } 255 weaponnull256 func weapon(at index: Int32) -> Weapon? { let o = __t.offset(4); return o == 0 ? nil : Weapon.assign( 257 __t.indirect(__t.vector(at: o) + (index * 4)), 258 __t.bb) } 259 equiped<T: FlatBufferObject>null260 func equiped<T: FlatBufferObject>() -> T? { 261 let o = __t.offset(8); return o == 0 ? nil : __t.union(o) 262 } 263 getRootAsMonsternull264 static func getRootAsMonster(bb: ByteBuffer) -> LocalMonster { 265 LocalMonster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0)))) 266 } 267 268 @inlinable 269 static func createMonster( 270 builder: inout FlatBufferBuilder, 271 offset: Offset, 272 equipment: Equipment = .none, 273 equippedOffset: UOffset) -> Offset 274 { 275 let start = builder.startTable(with: 3) 276 builder.add(element: equippedOffset, def: 0, at: 8) 277 builder.add(offset: offset, at: 4) 278 builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 6) 279 return Offset(offset: builder.endTable(at: start)) 280 } 281 } 282 283 struct Weapon: FlatBufferObject { 284 285 var __buffer: ByteBuffer! { __t.bb } 286 287 static let offsets: (name: VOffset, dmg: VOffset) = (4, 6) 288 private var __t: Table 289 290 init(_ t: Table) { __t = t } 291 init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)} 292 293 var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int16.self, at: o) } 294 var nameVector: [UInt8]? { __t.getVector(at: 4) } 295 var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) } 296 assignnull297 static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(bb: bb, position: i)) } 298 299 @inlinable 300 static func createWeapon( 301 builder: inout FlatBufferBuilder, 302 offset: Offset, 303 dmg: Int16) -> Offset 304 { 305 let _start = builder.startTable(with: 2) 306 Weapon.add(builder: &builder, name: offset) 307 Weapon.add(builder: &builder, dmg: dmg) 308 return Weapon.end(builder: &builder, startOffset: _start) 309 } 310 311 @inlinable endnull312 static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset { 313 Offset(offset: builder.endTable(at: startOffset)) 314 } 315 316 @inlinable addnull317 static func add(builder: inout FlatBufferBuilder, name: Offset) { 318 builder.add(offset: name, at: Weapon.offsets.name) 319 } 320 321 @inlinable addnull322 static func add(builder: inout FlatBufferBuilder, dmg: Int16) { 323 builder.add(element: dmg, def: 0, at: Weapon.offsets.dmg) 324 } 325 } 326